From f5642913c9b11e1b3b24ba20b5c696dd48b9d37f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20Bostr=C3=B6m?= Date: Fri, 12 Jun 2015 13:13:36 +0200 Subject: [PATCH] Remove webrtc/libjingle/{examples,session}. webrtc/libjingle/ is deprecated and these targets (unlike xmllite/xmpp) are not currently in use in Chromium (which blocks removing the whole webrtc/libjingle/ folder). BUG= R=juberti@webrtc.org Review URL: https://codereview.webrtc.org/1175243003. Cr-Commit-Position: refs/heads/master@{#9428} --- webrtc/libjingle/examples/call/Info.plist | 11 - webrtc/libjingle/examples/call/call_main.cc | 484 --- .../libjingle/examples/call/call_unittest.cc | 37 - webrtc/libjingle/examples/call/callclient.cc | 1617 -------- webrtc/libjingle/examples/call/callclient.h | 352 -- .../examples/call/callclient_unittest.cc | 47 - webrtc/libjingle/examples/call/console.cc | 169 - webrtc/libjingle/examples/call/console.h | 70 - .../examples/call/friendinvitesendtask.cc | 76 - .../examples/call/friendinvitesendtask.h | 49 - .../examples/call/mediaenginefactory.cc | 81 - .../examples/call/mediaenginefactory.h | 40 - webrtc/libjingle/examples/call/muc.h | 66 - .../examples/call/mucinviterecvtask.cc | 124 - .../examples/call/mucinviterecvtask.h | 82 - .../examples/call/mucinvitesendtask.cc | 63 - .../examples/call/mucinvitesendtask.h | 50 - .../examples/call/presencepushtask.cc | 222 -- .../examples/call/presencepushtask.h | 70 - webrtc/libjingle/examples/login/login_main.cc | 67 - webrtc/libjingle/libjingle.gyp | 159 - webrtc/libjingle/session/constants.cc | 217 -- webrtc/libjingle/session/constants.h | 219 -- webrtc/libjingle/session/media/call.cc | 1134 ------ webrtc/libjingle/session/media/call.h | 308 -- .../libjingle/session/media/mediamessages.cc | 332 -- .../libjingle/session/media/mediamessages.h | 98 - .../session/media/mediamessages_unittest.cc | 363 -- .../session/media/mediasessionclient.cc | 1160 ------ .../session/media/mediasessionclient.h | 175 - .../media/mediasessionclient_unittest.cc | 3324 ----------------- .../libjingle/session/p2ptransportparser.cc | 216 -- webrtc/libjingle/session/p2ptransportparser.h | 67 - webrtc/libjingle/session/parsing.cc | 141 - webrtc/libjingle/session/parsing.h | 140 - .../libjingle/session/rawtransportparser.cc | 92 - webrtc/libjingle/session/rawtransportparser.h | 49 - webrtc/libjingle/session/session_unittest.cc | 2430 ------------ webrtc/libjingle/session/sessionclient.h | 80 - webrtc/libjingle/session/sessionmanager.cc | 1150 ------ webrtc/libjingle/session/sessionmanager.h | 436 --- webrtc/libjingle/session/sessionmanagertask.h | 76 - webrtc/libjingle/session/sessionmessages.cc | 1132 ------ webrtc/libjingle/session/sessionmessages.h | 219 -- webrtc/libjingle/session/sessionsendtask.h | 128 - webrtc/libjingle/session/transportparser.cc | 38 - webrtc/libjingle/session/transportparser.h | 78 - .../session/transportparser_unittest.cc | 136 - .../session/tunnel/pseudotcpchannel.cc | 605 --- .../session/tunnel/pseudotcpchannel.h | 140 - .../tunnel/securetunnelsessionclient.cc | 397 -- .../tunnel/securetunnelsessionclient.h | 165 - .../session/tunnel/tunnelsessionclient.cc | 432 --- .../session/tunnel/tunnelsessionclient.h | 182 - .../tunnel/tunnelsessionclient_unittest.cc | 226 -- 55 files changed, 20021 deletions(-) delete mode 100644 webrtc/libjingle/examples/call/Info.plist delete mode 100644 webrtc/libjingle/examples/call/call_main.cc delete mode 100644 webrtc/libjingle/examples/call/call_unittest.cc delete mode 100644 webrtc/libjingle/examples/call/callclient.cc delete mode 100644 webrtc/libjingle/examples/call/callclient.h delete mode 100644 webrtc/libjingle/examples/call/callclient_unittest.cc delete mode 100644 webrtc/libjingle/examples/call/console.cc delete mode 100644 webrtc/libjingle/examples/call/console.h delete mode 100644 webrtc/libjingle/examples/call/friendinvitesendtask.cc delete mode 100644 webrtc/libjingle/examples/call/friendinvitesendtask.h delete mode 100644 webrtc/libjingle/examples/call/mediaenginefactory.cc delete mode 100644 webrtc/libjingle/examples/call/mediaenginefactory.h delete mode 100644 webrtc/libjingle/examples/call/muc.h delete mode 100644 webrtc/libjingle/examples/call/mucinviterecvtask.cc delete mode 100644 webrtc/libjingle/examples/call/mucinviterecvtask.h delete mode 100644 webrtc/libjingle/examples/call/mucinvitesendtask.cc delete mode 100644 webrtc/libjingle/examples/call/mucinvitesendtask.h delete mode 100644 webrtc/libjingle/examples/call/presencepushtask.cc delete mode 100644 webrtc/libjingle/examples/call/presencepushtask.h delete mode 100644 webrtc/libjingle/examples/login/login_main.cc delete mode 100644 webrtc/libjingle/session/constants.cc delete mode 100644 webrtc/libjingle/session/constants.h delete mode 100644 webrtc/libjingle/session/media/call.cc delete mode 100644 webrtc/libjingle/session/media/call.h delete mode 100644 webrtc/libjingle/session/media/mediamessages.cc delete mode 100644 webrtc/libjingle/session/media/mediamessages.h delete mode 100644 webrtc/libjingle/session/media/mediamessages_unittest.cc delete mode 100644 webrtc/libjingle/session/media/mediasessionclient.cc delete mode 100644 webrtc/libjingle/session/media/mediasessionclient.h delete mode 100644 webrtc/libjingle/session/media/mediasessionclient_unittest.cc delete mode 100644 webrtc/libjingle/session/p2ptransportparser.cc delete mode 100644 webrtc/libjingle/session/p2ptransportparser.h delete mode 100644 webrtc/libjingle/session/parsing.cc delete mode 100644 webrtc/libjingle/session/parsing.h delete mode 100644 webrtc/libjingle/session/rawtransportparser.cc delete mode 100644 webrtc/libjingle/session/rawtransportparser.h delete mode 100644 webrtc/libjingle/session/session_unittest.cc delete mode 100644 webrtc/libjingle/session/sessionclient.h delete mode 100644 webrtc/libjingle/session/sessionmanager.cc delete mode 100644 webrtc/libjingle/session/sessionmanager.h delete mode 100644 webrtc/libjingle/session/sessionmanagertask.h delete mode 100644 webrtc/libjingle/session/sessionmessages.cc delete mode 100644 webrtc/libjingle/session/sessionmessages.h delete mode 100644 webrtc/libjingle/session/sessionsendtask.h delete mode 100644 webrtc/libjingle/session/transportparser.cc delete mode 100644 webrtc/libjingle/session/transportparser.h delete mode 100644 webrtc/libjingle/session/transportparser_unittest.cc delete mode 100644 webrtc/libjingle/session/tunnel/pseudotcpchannel.cc delete mode 100644 webrtc/libjingle/session/tunnel/pseudotcpchannel.h delete mode 100644 webrtc/libjingle/session/tunnel/securetunnelsessionclient.cc delete mode 100644 webrtc/libjingle/session/tunnel/securetunnelsessionclient.h delete mode 100644 webrtc/libjingle/session/tunnel/tunnelsessionclient.cc delete mode 100644 webrtc/libjingle/session/tunnel/tunnelsessionclient.h delete mode 100644 webrtc/libjingle/session/tunnel/tunnelsessionclient_unittest.cc diff --git a/webrtc/libjingle/examples/call/Info.plist b/webrtc/libjingle/examples/call/Info.plist deleted file mode 100644 index a59cfa591..000000000 --- a/webrtc/libjingle/examples/call/Info.plist +++ /dev/null @@ -1,11 +0,0 @@ - - - - - CFBundleIdentifier - com.google.call - CFBundleName - call - - - diff --git a/webrtc/libjingle/examples/call/call_main.cc b/webrtc/libjingle/examples/call/call_main.cc deleted file mode 100644 index 2deb78a71..000000000 --- a/webrtc/libjingle/examples/call/call_main.cc +++ /dev/null @@ -1,484 +0,0 @@ -/* - * 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 -#include -#include - -#include -#include -#include - -#include "webrtc/base/flags.h" -#include "webrtc/base/logging.h" -#ifdef OSX -#include "webrtc/base/maccocoasocketserver.h" -#endif -#include "talk/examples/call/callclient.h" -#include "talk/examples/call/console.h" -#include "talk/examples/call/mediaenginefactory.h" -#include "talk/session/media/srtpfilter.h" -#include "webrtc/base/pathutils.h" -#include "webrtc/base/ssladapter.h" -#include "webrtc/base/stream.h" -#include "webrtc/base/win32socketserver.h" -#include "webrtc/libjingle/session/media/mediasessionclient.h" -#include "webrtc/libjingle/xmpp/xmppauth.h" -#include "webrtc/libjingle/xmpp/xmppclientsettings.h" -#include "webrtc/libjingle/xmpp/xmpppump.h" -#include "webrtc/libjingle/xmpp/xmppsocket.h" -#include "webrtc/p2p/base/constants.h" - -class DebugLog : public sigslot::has_slots<> { - public: - DebugLog() : - debug_input_buf_(NULL), debug_input_len_(0), debug_input_alloc_(0), - debug_output_buf_(NULL), debug_output_len_(0), debug_output_alloc_(0), - censor_password_(false) - {} - char * debug_input_buf_; - int debug_input_len_; - int debug_input_alloc_; - char * debug_output_buf_; - int debug_output_len_; - int debug_output_alloc_; - bool censor_password_; - - void Input(const char * data, int len) { - if (debug_input_len_ + len > debug_input_alloc_) { - char * old_buf = debug_input_buf_; - debug_input_alloc_ = 4096; - while (debug_input_alloc_ < debug_input_len_ + len) { - debug_input_alloc_ *= 2; - } - debug_input_buf_ = new char[debug_input_alloc_]; - memcpy(debug_input_buf_, old_buf, debug_input_len_); - delete[] old_buf; - } - memcpy(debug_input_buf_ + debug_input_len_, data, len); - debug_input_len_ += len; - DebugPrint(debug_input_buf_, &debug_input_len_, false); - } - - void Output(const char * data, int len) { - if (debug_output_len_ + len > debug_output_alloc_) { - char * old_buf = debug_output_buf_; - debug_output_alloc_ = 4096; - while (debug_output_alloc_ < debug_output_len_ + len) { - debug_output_alloc_ *= 2; - } - debug_output_buf_ = new char[debug_output_alloc_]; - memcpy(debug_output_buf_, old_buf, debug_output_len_); - delete[] old_buf; - } - memcpy(debug_output_buf_ + debug_output_len_, data, len); - debug_output_len_ += len; - DebugPrint(debug_output_buf_, &debug_output_len_, true); - } - - static bool IsAuthTag(const char * str, size_t len) { - if (str[0] == '<' && str[1] == 'a' && - str[2] == 'u' && - str[3] == 't' && - str[4] == 'h' && - str[5] <= ' ') { - std::string tag(str, len); - - if (tag.find("mechanism") != std::string::npos) - return true; - } - return false; - } - - void DebugPrint(char * buf, int * plen, bool output) { - int len = *plen; - if (len > 0) { - time_t tim = time(NULL); - struct tm * now = localtime(&tim); - char *time_string = asctime(now); - if (time_string) { - size_t time_len = strlen(time_string); - if (time_len > 0) { - time_string[time_len-1] = 0; // trim off terminating \n - } - } - LOG(INFO) << (output ? "SEND >>>>>>>>>>>>>>>>" : "RECV <<<<<<<<<<<<<<<<") - << " : " << time_string; - - bool indent; - int start = 0, nest = 3; - for (int i = 0; i < len; i += 1) { - if (buf[i] == '>') { - if ((i > 0) && (buf[i-1] == '/')) { - indent = false; - } else if ((start + 1 < len) && (buf[start + 1] == '/')) { - indent = false; - nest -= 2; - } else { - indent = true; - } - - // Output a tag - LOG(INFO) << std::setw(nest) << " " - << std::string(buf + start, i + 1 - start); - - if (indent) - nest += 2; - - // Note if it's a PLAIN auth tag - if (IsAuthTag(buf + start, i + 1 - start)) { - censor_password_ = true; - } - - // incr - start = i + 1; - } - - if (buf[i] == '<' && start < i) { - if (censor_password_) { - LOG(INFO) << std::setw(nest) << " " << "## TEXT REMOVED ##"; - censor_password_ = false; - } else { - LOG(INFO) << std::setw(nest) << " " - << std::string(buf + start, i - start); - } - start = i; - } - } - len = len - start; - memcpy(buf, buf + start, len); - *plen = len; - } - } -}; - -static DebugLog debug_log_; -static const int DEFAULT_PORT = 5222; - -#ifdef ANDROID -static std::vector codecs; -static const cricket::AudioCodec ISAC(103, "ISAC", 40000, 16000, 1, 0); - -cricket::MediaEngineInterface *CreateAndroidMediaEngine() { - cricket::FakeMediaEngine *engine = new cricket::FakeMediaEngine(); - - codecs.push_back(ISAC); - engine->SetAudioCodecs(codecs); - return engine; -} -#endif - -// TODO: Move this into Console. -void Print(const char* chars) { - printf("%s", chars); - fflush(stdout); -} - -bool GetSecurePolicy(const std::string& in, cricket::SecurePolicy* out) { - if (in == "disable") { - *out = cricket::SEC_DISABLED; - } else if (in == "enable") { - *out = cricket::SEC_ENABLED; - } else if (in == "require") { - *out = cricket::SEC_REQUIRED; - } else { - return false; - } - return true; -} - -int main(int argc, char **argv) { - // This app has three threads. The main thread will run the XMPP client, - // which will print to the screen in its own thread. A second thread - // will get input from the console, parse it, and pass the appropriate - // message back to the XMPP client's thread. A third thread is used - // by MediaSessionClient as its worker thread. - - // define options - DEFINE_string(s, "talk.google.com", "The connection server to use."); - DEFINE_string(tls, "require", - "Select connection encryption: disable, enable, require."); - DEFINE_bool(allowplain, false, "Allow plain authentication."); - DEFINE_bool(testserver, false, "Use test server."); - DEFINE_string(oauth, "", "OAuth2 access token."); - DEFINE_bool(a, false, "Turn on auto accept for incoming calls."); - DEFINE_string(signaling, "hybrid", - "Initial signaling protocol to use: jingle, gingle, or hybrid."); - DEFINE_string(transport, "hybrid", - "Initial transport protocol to use: ice, gice, or hybrid."); - DEFINE_string(sdes, "enable", - "Select SDES media encryption: disable, enable, require."); - DEFINE_string(dtls, "disable", - "Select DTLS transport encryption: disable, enable, require."); - DEFINE_int(portallocator, 0, "Filter out unwanted connection types."); - DEFINE_string(pmuc, "groupchat.google.com", "The persistant muc domain."); - DEFINE_string(capsnode, "http://code.google.com/p/libjingle/call", - "Caps node: A URI identifying the app."); - DEFINE_string(capsver, "0.6", - "Caps ver: A string identifying the version of the app."); - DEFINE_string(voiceinput, NULL, "RTP dump file for voice input."); - DEFINE_string(voiceoutput, NULL, "RTP dump file for voice output."); - DEFINE_string(videoinput, NULL, "RTP dump file for video input."); - DEFINE_string(videooutput, NULL, "RTP dump file for video output."); - DEFINE_bool(render, true, "Renders the video."); - DEFINE_string(datachannel, "", - "Enable a data channel, and choose the type: rtp or sctp."); - DEFINE_bool(d, false, "Turn on debugging."); - DEFINE_bool(debugsrtp, false, "Enable debugging for srtp."); - DEFINE_bool(help, false, "Prints this message"); - DEFINE_bool(multisession, false, - "Enable support for multiple sessions in calls."); - DEFINE_bool(roster, false, - "Enable roster messages printed in console."); - - // parse options - rtc::FlagList::SetFlagsFromCommandLine(&argc, argv, true); - if (FLAG_help) { - rtc::FlagList::Print(NULL, false); - return 0; - } - - bool auto_accept = FLAG_a; - bool debug = FLAG_d; - std::string signaling = FLAG_signaling; - std::string transport = FLAG_transport; - bool test_server = FLAG_testserver; - bool allow_plain = FLAG_allowplain; - std::string tls = FLAG_tls; - std::string oauth_token = FLAG_oauth; - int32 portallocator_flags = FLAG_portallocator; - std::string pmuc_domain = FLAG_pmuc; - std::string server = FLAG_s; - std::string sdes = FLAG_sdes; - std::string dtls = FLAG_dtls; - std::string caps_node = FLAG_capsnode; - std::string caps_ver = FLAG_capsver; - bool debugsrtp = FLAG_debugsrtp; - bool render = FLAG_render; - std::string data_channel = FLAG_datachannel; - bool multisession_enabled = FLAG_multisession; - rtc::SSLIdentity* ssl_identity = NULL; - bool show_roster_messages = FLAG_roster; - - // Set up debugging. - if (debug) { - rtc::LogMessage::LogToDebug(rtc::LS_VERBOSE); - } - - if (debugsrtp) { - cricket::EnableSrtpDebugging(); - } - - // Set up the crypto subsystem. - rtc::InitializeSSL(); - - // Parse username and password, if present. - buzz::Jid jid; - std::string username; - rtc::InsecureCryptStringImpl pass; - if (argc > 1) { - username = argv[1]; - if (argc > 2) { - pass.password() = argv[2]; - } - } - - if (username.empty()) { - Print("JID: "); - std::cin >> username; - } - if (username.find('@') == std::string::npos) { - username.append("@localhost"); - } - jid = buzz::Jid(username); - if (!jid.IsValid() || jid.node() == "") { - Print("Invalid JID. JIDs should be in the form user@domain\n"); - return 1; - } - if (pass.password().empty() && !test_server && oauth_token.empty()) { - Console::SetEcho(false); - Print("Password: "); - std::cin >> pass.password(); - Console::SetEcho(true); - Print("\n"); - } - - // Decide on the connection settings. - buzz::XmppClientSettings xcs; - xcs.set_user(jid.node()); - xcs.set_resource("call"); - xcs.set_host(jid.domain()); - xcs.set_allow_plain(allow_plain); - - if (tls == "disable") { - xcs.set_use_tls(buzz::TLS_DISABLED); - } else if (tls == "enable") { - xcs.set_use_tls(buzz::TLS_ENABLED); - } else if (tls == "require") { - xcs.set_use_tls(buzz::TLS_REQUIRED); - } else { - Print("Invalid TLS option, must be enable, disable, or require.\n"); - return 1; - } - - if (test_server) { - pass.password() = jid.node(); - xcs.set_allow_plain(true); - xcs.set_use_tls(buzz::TLS_DISABLED); - xcs.set_test_server_domain("google.com"); - } - xcs.set_pass(rtc::CryptString(pass)); - if (!oauth_token.empty()) { - xcs.set_auth_token(buzz::AUTH_MECHANISM_OAUTH2, oauth_token); - } - - std::string host; - int port; - - int colon = server.find(':'); - if (colon == -1) { - host = server; - port = DEFAULT_PORT; - } else { - host = server.substr(0, colon); - port = atoi(server.substr(colon + 1).c_str()); - } - - xcs.set_server(rtc::SocketAddress(host, port)); - - // Decide on the signaling and crypto settings. - cricket::SignalingProtocol signaling_protocol = cricket::PROTOCOL_HYBRID; - if (signaling == "jingle") { - signaling_protocol = cricket::PROTOCOL_JINGLE; - } else if (signaling == "gingle") { - signaling_protocol = cricket::PROTOCOL_GINGLE; - } else if (signaling == "hybrid") { - signaling_protocol = cricket::PROTOCOL_HYBRID; - } else { - Print("Invalid signaling protocol. Must be jingle, gingle, or hybrid.\n"); - return 1; - } - - cricket::TransportProtocol transport_protocol = cricket::ICEPROTO_HYBRID; - if (transport == "ice") { - transport_protocol = cricket::ICEPROTO_RFC5245; - } else if (transport == "gice") { - transport_protocol = cricket::ICEPROTO_GOOGLE; - } else if (transport == "hybrid") { - transport_protocol = cricket::ICEPROTO_HYBRID; - } else { - Print("Invalid transport protocol. Must be ice, gice, or hybrid.\n"); - return 1; - } - - cricket::DataChannelType data_channel_type = cricket::DCT_NONE; - if (data_channel == "rtp") { - data_channel_type = cricket::DCT_RTP; - } else if (data_channel == "sctp") { - data_channel_type = cricket::DCT_SCTP; - } else if (!data_channel.empty()) { - Print("Invalid data channel type. Must be rtp or sctp.\n"); - return 1; - } - - cricket::SecurePolicy sdes_policy, dtls_policy; - if (!GetSecurePolicy(sdes, &sdes_policy)) { - Print("Invalid SDES policy. Must be enable, disable, or require.\n"); - return 1; - } - if (!GetSecurePolicy(dtls, &dtls_policy)) { - Print("Invalid DTLS policy. Must be enable, disable, or require.\n"); - return 1; - } - if (dtls_policy != cricket::SEC_DISABLED) { - ssl_identity = rtc::SSLIdentity::Generate(jid.Str()); - if (!ssl_identity) { - Print("Failed to generate identity for DTLS.\n"); - return 1; - } - } - -#ifdef ANDROID - MediaEngineFactory::SetCreateFunction(&CreateAndroidMediaEngine); -#endif - -#if WIN32 - // Need to pump messages on our main thread on Windows. - rtc::Win32Thread w32_thread; - rtc::ThreadManager::Instance()->SetCurrentThread(&w32_thread); -#endif - rtc::Thread* main_thread = rtc::Thread::Current(); -#ifdef OSX - rtc::MacCocoaSocketServer ss; - rtc::SocketServerScope ss_scope(&ss); -#endif - - buzz::XmppPump pump; - CallClient *client = new CallClient(pump.client(), caps_node, caps_ver); - - if (FLAG_voiceinput || FLAG_voiceoutput || - FLAG_videoinput || FLAG_videooutput) { - // If any dump file is specified, we use a FileMediaEngine. - cricket::MediaEngineInterface* engine = - MediaEngineFactory::CreateFileMediaEngine( - FLAG_voiceinput, FLAG_voiceoutput, - FLAG_videoinput, FLAG_videooutput); - client->SetMediaEngine(engine); - } - - Console *console = new Console(main_thread, client); - client->SetConsole(console); - client->SetAutoAccept(auto_accept); - client->SetPmucDomain(pmuc_domain); - client->SetPortAllocatorFlags(portallocator_flags); - client->SetAllowLocalIps(true); - client->SetSignalingProtocol(signaling_protocol); - client->SetTransportProtocol(transport_protocol); - client->SetSecurePolicy(sdes_policy, dtls_policy); - client->SetSslIdentity(ssl_identity); - client->SetRender(render); - client->SetDataChannelType(data_channel_type); - client->SetMultiSessionEnabled(multisession_enabled); - client->SetShowRosterMessages(show_roster_messages); - console->Start(); - - if (debug) { - pump.client()->SignalLogInput.connect(&debug_log_, &DebugLog::Input); - pump.client()->SignalLogOutput.connect(&debug_log_, &DebugLog::Output); - } - - Print(("Logging in to " + server + " as " + jid.Str() + "\n").c_str()); - pump.DoLogin(xcs, new buzz::XmppSocket(buzz::TLS_REQUIRED), new XmppAuth()); - main_thread->Run(); - pump.DoDisconnect(); - - console->Stop(); - delete console; - delete client; - - return 0; -} diff --git a/webrtc/libjingle/examples/call/call_unittest.cc b/webrtc/libjingle/examples/call/call_unittest.cc deleted file mode 100644 index cc2878fce..000000000 --- a/webrtc/libjingle/examples/call/call_unittest.cc +++ /dev/null @@ -1,37 +0,0 @@ -/* - * libjingle - * Copyright 2008, 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. - */ - -// Main function for all unit tests in talk/examples/call - -#include "testing/base/public/gunit.h" -#include "webrtc/base/logging.h" - -int main(int argc, char **argv) { - rtc::LogMessage::LogToDebug(rtc::LogMessage::NO_LOGGING); - testing::ParseGUnitFlags(&argc, argv); - return RUN_ALL_TESTS(); -} diff --git a/webrtc/libjingle/examples/call/callclient.cc b/webrtc/libjingle/examples/call/callclient.cc deleted file mode 100644 index b2c5c946b..000000000 --- a/webrtc/libjingle/examples/call/callclient.cc +++ /dev/null @@ -1,1617 +0,0 @@ -/* - * 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/examples/call/callclient.h" - -#include - -#include "talk/examples/call/console.h" -#include "talk/examples/call/friendinvitesendtask.h" -#include "talk/examples/call/muc.h" -#include "talk/examples/call/mucinviterecvtask.h" -#include "talk/examples/call/mucinvitesendtask.h" -#include "talk/examples/call/presencepushtask.h" -#include "talk/media/base/mediacommon.h" -#include "talk/media/base/mediaengine.h" -#include "talk/media/base/rtpdataengine.h" -#include "talk/media/base/screencastid.h" -#ifdef HAVE_SCTP -#include "talk/media/sctp/sctpdataengine.h" -#endif -#include "talk/media/base/videorenderer.h" -#include "talk/media/devices/devicemanager.h" -#include "talk/media/devices/videorendererfactory.h" -#include "webrtc/base/helpers.h" -#include "webrtc/base/logging.h" -#include "webrtc/base/network.h" -#include "webrtc/base/socketaddress.h" -#include "webrtc/base/stringencode.h" -#include "webrtc/base/stringutils.h" -#include "webrtc/base/thread.h" -#include "webrtc/base/windowpickerfactory.h" -#include "webrtc/libjingle/session/media/mediamessages.h" -#include "webrtc/libjingle/session/media/mediasessionclient.h" -#include "webrtc/libjingle/session/sessionmanager.h" -#include "webrtc/libjingle/xmpp/constants.h" -#include "webrtc/libjingle/xmpp/hangoutpubsubclient.h" -#include "webrtc/libjingle/xmpp/mucroomconfigtask.h" -#include "webrtc/libjingle/xmpp/mucroomlookuptask.h" -#include "webrtc/libjingle/xmpp/pingtask.h" -#include "webrtc/libjingle/xmpp/presenceouttask.h" -#include "webrtc/p2p/client/basicportallocator.h" -#include "webrtc/p2p/client/sessionmanagertask.h" - -namespace { - -// Must be period >= timeout. -const uint32 kPingPeriodMillis = 10000; -const uint32 kPingTimeoutMillis = 10000; - -const char* DescribeStatus(buzz::PresenceStatus::Show show, - const std::string& desc) { - switch (show) { - case buzz::PresenceStatus::SHOW_XA: return desc.c_str(); - case buzz::PresenceStatus::SHOW_ONLINE: return "online"; - case buzz::PresenceStatus::SHOW_AWAY: return "away"; - case buzz::PresenceStatus::SHOW_DND: return "do not disturb"; - case buzz::PresenceStatus::SHOW_CHAT: return "ready to chat"; - default: return "offline"; - } -} - -std::string GetWord(const std::vector& words, - size_t index, const std::string& def) { - if (words.size() > index) { - return words[index]; - } else { - return def; - } -} - -int GetInt(const std::vector& words, size_t index, int def) { - int val; - if (words.size() > index && rtc::FromString(words[index], &val)) { - return val; - } else { - return def; - } -} - -} // namespace - -const char* CALL_COMMANDS = -"Available commands:\n" -"\n" -" hangup Ends the call.\n" -" hold Puts the current call on hold\n" -" calls Lists the current calls and their sessions\n" -" switch [call_id] Switch to the specified call\n" -" addsession [jid] Add a new session to the current call.\n" -" rmsession [sid] Remove specified session.\n" -" mute Stops sending voice.\n" -" unmute Re-starts sending voice.\n" -" vmute Stops sending video.\n" -" vunmute Re-starts sending video.\n" -" dtmf Sends a DTMF tone.\n" -" stats Print voice stats for the current call.\n" -" quit Quits the application.\n" -""; - -// TODO: Make present and record really work. -const char* HANGOUT_COMMANDS = -"Available MUC commands:\n" -"\n" -" present Starts presenting (just signalling; not actually presenting.)\n" -" unpresent Stops presenting (just signalling; not actually presenting.)\n" -" record Starts recording (just signalling; not actually recording.)\n" -" unrecord Stops recording (just signalling; not actually recording.)\n" -" rmute [nick] Remote mute another participant.\n" -" block [nick] Block another participant.\n" -" screencast [fps] Starts screencast. \n" -" unscreencast Stops screencast. \n" -" quit Quits the application.\n" -""; - -const char* RECEIVE_COMMANDS = -"Available commands:\n" -"\n" -" accept [bw] Accepts the incoming call and switches to it.\n" -" reject Rejects the incoming call and stays with the current call.\n" -" quit Quits the application.\n" -""; - -const char* CONSOLE_COMMANDS = -"Available commands:\n" -"\n" -" roster Prints the online friends from your roster.\n" -" friend user Request to add a user to your roster.\n" -" call [jid] [bw] Initiates a call to the user[/room] with the\n" -" given JID and with optional bandwidth.\n" -" vcall [jid] [bw] Initiates a video call to the user[/room] with\n" -" the given JID and with optional bandwidth.\n" -" calls Lists the current calls\n" -" switch [call_id] Switch to the specified call\n" -" join [room_jid] Joins a multi-user-chat with room JID.\n" -" ljoin [room_name] Joins a MUC by looking up JID from room name.\n" -" invite user [room] Invites a friend to a multi-user-chat.\n" -" leave [room] Leaves a multi-user-chat.\n" -" nick [nick] Sets the nick.\n" -" priority [int] Sets the priority.\n" -" getdevs Prints the available media devices.\n" -" quit Quits the application.\n" -""; - -void CallClient::ParseLine(const std::string& line) { - std::vector words; - int start = -1; - int state = 0; - for (int index = 0; index <= static_cast(line.size()); ++index) { - if (state == 0) { - if (!isspace(line[index])) { - start = index; - state = 1; - } - } else { - ASSERT(state == 1); - ASSERT(start >= 0); - if (isspace(line[index])) { - std::string word(line, start, index - start); - words.push_back(word); - start = -1; - state = 0; - } - } - } - - // Global commands - const std::string& command = GetWord(words, 0, ""); - if (command == "quit") { - Quit(); - } else if (call_ && incoming_call_) { - if (command == "accept") { - cricket::CallOptions options; - options.video_bandwidth = GetInt(words, 1, cricket::kAutoBandwidth); - options.has_video = true; - options.data_channel_type = data_channel_type_; - Accept(options); - } else if (command == "reject") { - Reject(); - } else { - console_->PrintLine(RECEIVE_COMMANDS); - } - } else if (call_) { - if (command == "hangup") { - call_->Terminate(); - } else if (command == "hold") { - media_client_->SetFocus(NULL); - call_ = NULL; - } else if (command == "addsession") { - std::string to = GetWord(words, 1, ""); - cricket::CallOptions options; - options.has_video = call_->has_video(); - options.video_bandwidth = cricket::kAutoBandwidth; - options.data_channel_type = data_channel_type_; - options.AddStream(cricket::MEDIA_TYPE_VIDEO, "", ""); - if (!InitiateAdditionalSession(to, options)) { - console_->PrintLine("Failed to initiate additional session."); - } - } else if (command == "rmsession") { - std::string id = GetWord(words, 1, ""); - TerminateAndRemoveSession(call_, id); - } else if (command == "calls") { - PrintCalls(); - } else if ((words.size() == 2) && (command == "switch")) { - SwitchToCall(GetInt(words, 1, -1)); - } else if (command == "mute") { - call_->Mute(true); - if (InMuc()) { - hangout_pubsub_client_->PublishAudioMuteState(true); - } - } else if (command == "unmute") { - call_->Mute(false); - if (InMuc()) { - hangout_pubsub_client_->PublishAudioMuteState(false); - } - } else if (command == "vmute") { - call_->MuteVideo(true); - if (InMuc()) { - hangout_pubsub_client_->PublishVideoMuteState(true); - } - } else if (command == "vunmute") { - call_->MuteVideo(false); - if (InMuc()) { - hangout_pubsub_client_->PublishVideoMuteState(false); - } - } else if (command == "screencast") { - if (screencast_ssrc_ != 0) { - console_->PrintLine("Can't screencast twice. Unscreencast first."); - } else { - std::string streamid = "screencast"; - screencast_ssrc_ = rtc::CreateRandomId(); - int fps = GetInt(words, 1, 5); // Default to 5 fps. - - cricket::ScreencastId screencastid; - cricket::Session* session = GetFirstSession(); - if (session && SelectFirstDesktopScreencastId(&screencastid)) { - call_->StartScreencast( - session, streamid, screencast_ssrc_, screencastid, fps); - } - } - } else if (command == "unscreencast") { - // TODO: Use a random ssrc - std::string streamid = "screencast"; - - cricket::Session* session = GetFirstSession(); - if (session) { - call_->StopScreencast(session, streamid, screencast_ssrc_); - screencast_ssrc_ = 0; - } - } else if (command == "present") { - if (InMuc()) { - hangout_pubsub_client_->PublishPresenterState(true); - } - } else if (command == "unpresent") { - if (InMuc()) { - hangout_pubsub_client_->PublishPresenterState(false); - } - } else if (command == "record") { - if (InMuc()) { - hangout_pubsub_client_->PublishRecordingState(true); - } - } else if (command == "unrecord") { - if (InMuc()) { - hangout_pubsub_client_->PublishRecordingState(false); - } - } else if ((command == "rmute") && (words.size() == 2)) { - if (InMuc()) { - const std::string& nick = words[1]; - hangout_pubsub_client_->RemoteMute(nick); - } - } else if ((command == "block") && (words.size() == 2)) { - if (InMuc()) { - const std::string& nick = words[1]; - hangout_pubsub_client_->BlockMedia(nick); - } - } else if (command == "senddata") { - // "" is the default streamid. - SendData("", words[1]); - } else if ((command == "dtmf") && (words.size() == 2)) { - int ev = std::string("0123456789*#").find(words[1][0]); - call_->PressDTMF(ev); - } else if (command == "stats") { - PrintStats(); - } else { - console_->PrintLine(CALL_COMMANDS); - if (InMuc()) { - console_->PrintLine(HANGOUT_COMMANDS); - } - } - } else { - if (command == "roster") { - PrintRoster(); - } else if (command == "send") { - buzz::Jid jid(words[1]); - if (jid.IsValid()) { - last_sent_to_ = words[1]; - SendChat(words[1], words[2]); - } else if (!last_sent_to_.empty()) { - SendChat(last_sent_to_, words[1]); - } else { - console_->PrintLine( - "Invalid JID. JIDs should be in the form user@domain"); - } - } else if ((words.size() == 2) && (command == "friend")) { - InviteFriend(words[1]); - } else if (command == "call") { - std::string to = GetWord(words, 1, ""); - cricket::CallOptions options; - options.data_channel_type = data_channel_type_; - if (!PlaceCall(to, options)) { - console_->PrintLine("Failed to initiate call."); - } - } else if (command == "vcall") { - std::string to = GetWord(words, 1, ""); - int bandwidth = GetInt(words, 2, cricket::kAutoBandwidth); - cricket::CallOptions options; - options.has_video = true; - options.video_bandwidth = bandwidth; - options.data_channel_type = data_channel_type_; - if (!PlaceCall(to, options)) { - console_->PrintLine("Failed to initiate call."); - } - } else if (command == "calls") { - PrintCalls(); - } else if ((words.size() == 2) && (command == "switch")) { - SwitchToCall(GetInt(words, 1, -1)); - } else if (command == "join") { - JoinMuc(GetWord(words, 1, "")); - } else if (command == "ljoin") { - LookupAndJoinMuc(GetWord(words, 1, "")); - } else if ((words.size() >= 2) && (command == "invite")) { - InviteToMuc(words[1], GetWord(words, 2, "")); - } else if (command == "leave") { - LeaveMuc(GetWord(words, 1, "")); - } else if (command == "nick") { - SetNick(GetWord(words, 1, "")); - } else if (command == "priority") { - int priority = GetInt(words, 1, 0); - SetPriority(priority); - SendStatus(); - } else if (command == "getdevs") { - GetDevices(); - } else if ((words.size() == 2) && (command == "setvol")) { - SetVolume(words[1]); - } else { - console_->PrintLine(CONSOLE_COMMANDS); - } - } -} - -CallClient::CallClient(buzz::XmppClient* xmpp_client, - const std::string& caps_node, const std::string& version) - : xmpp_client_(xmpp_client), - worker_thread_(NULL), - media_engine_(NULL), - data_engine_(NULL), - media_client_(NULL), - call_(NULL), - hangout_pubsub_client_(NULL), - incoming_call_(false), - auto_accept_(false), - pmuc_domain_("groupchat.google.com"), - render_(true), - data_channel_type_(cricket::DCT_NONE), - multisession_enabled_(false), - local_renderer_(NULL), - static_views_accumulated_count_(0), - screencast_ssrc_(0), - roster_(new RosterMap), - portallocator_flags_(0), - allow_local_ips_(false), - signaling_protocol_(cricket::PROTOCOL_HYBRID), - transport_protocol_(cricket::ICEPROTO_HYBRID), - sdes_policy_(cricket::SEC_DISABLED), - dtls_policy_(cricket::SEC_DISABLED), - ssl_identity_(), - show_roster_messages_(false) { - xmpp_client_->SignalStateChange.connect(this, &CallClient::OnStateChange); - my_status_.set_caps_node(caps_node); - my_status_.set_version(version); -} - -CallClient::~CallClient() { - delete media_client_; - delete roster_; - delete worker_thread_; -} - -const std::string CallClient::strerror(buzz::XmppEngine::Error err) { - switch (err) { - case buzz::XmppEngine::ERROR_NONE: - return ""; - case buzz::XmppEngine::ERROR_XML: - return "Malformed XML or encoding error"; - case buzz::XmppEngine::ERROR_STREAM: - return "XMPP stream error"; - case buzz::XmppEngine::ERROR_VERSION: - return "XMPP version error"; - case buzz::XmppEngine::ERROR_UNAUTHORIZED: - return "User is not authorized (Check your username and password)"; - case buzz::XmppEngine::ERROR_TLS: - return "TLS could not be negotiated"; - case buzz::XmppEngine::ERROR_AUTH: - return "Authentication could not be negotiated"; - case buzz::XmppEngine::ERROR_BIND: - return "Resource or session binding could not be negotiated"; - case buzz::XmppEngine::ERROR_CONNECTION_CLOSED: - return "Connection closed by output handler."; - case buzz::XmppEngine::ERROR_DOCUMENT_CLOSED: - return "Closed by "; - case buzz::XmppEngine::ERROR_SOCKET: - return "Socket error"; - default: - return "Unknown error"; - } -} - -void CallClient::OnCallDestroy(cricket::Call* call) { - RemoveCallsStaticRenderedViews(call); - if (call == call_) { - if (local_renderer_) { - delete local_renderer_; - local_renderer_ = NULL; - } - console_->PrintLine("call destroyed"); - call_ = NULL; - delete hangout_pubsub_client_; - hangout_pubsub_client_ = NULL; - } -} - -void CallClient::OnStateChange(buzz::XmppEngine::State state) { - switch (state) { - case buzz::XmppEngine::STATE_START: - console_->PrintLine("connecting..."); - break; - case buzz::XmppEngine::STATE_OPENING: - console_->PrintLine("logging in..."); - break; - case buzz::XmppEngine::STATE_OPEN: - console_->PrintLine("logged in..."); - InitMedia(); - InitPresence(); - break; - case buzz::XmppEngine::STATE_CLOSED: - { - buzz::XmppEngine::Error error = xmpp_client_->GetError(NULL); - console_->PrintLine("logged out... %s", strerror(error).c_str()); - Quit(); - } - break; - default: - break; - } -} - -void CallClient::InitMedia() { - worker_thread_ = new rtc::Thread(); - // The worker thread must be started here since initialization of - // the ChannelManager will generate messages that need to be - // dispatched by it. - worker_thread_->Start(); - - // TODO: It looks like we are leaking many objects. E.g. - // |network_manager_| is never deleted. - network_manager_ = new rtc::BasicNetworkManager(); - - // TODO: Decide if the relay address should be specified here. - rtc::SocketAddress stun_addr("stun.l.google.com", 19302); - cricket::ServerAddresses stun_servers; - stun_servers.insert(stun_addr); - port_allocator_ = new cricket::BasicPortAllocator( - network_manager_, stun_servers, rtc::SocketAddress(), - rtc::SocketAddress(), rtc::SocketAddress()); - - if (portallocator_flags_ != 0) { - port_allocator_->set_flags(portallocator_flags_); - } - session_manager_ = new cricket::SessionManager( - port_allocator_, worker_thread_); - session_manager_->set_secure(dtls_policy_); - session_manager_->set_identity(ssl_identity_.get()); - session_manager_->set_transport_protocol(transport_protocol_); - session_manager_->SignalRequestSignaling.connect( - this, &CallClient::OnRequestSignaling); - session_manager_->SignalSessionCreate.connect( - this, &CallClient::OnSessionCreate); - session_manager_->OnSignalingReady(); - - session_manager_task_ = - new cricket::SessionManagerTask(xmpp_client_, session_manager_); - session_manager_task_->EnableOutgoingMessages(); - session_manager_task_->Start(); - - if (!media_engine_) { - media_engine_ = cricket::MediaEngineFactory::Create(); - } - - if (!data_engine_) { - if (data_channel_type_ == cricket::DCT_SCTP) { -#ifdef HAVE_SCTP - data_engine_ = new cricket::SctpDataEngine(); -#else - LOG(LS_WARNING) << "SCTP Data Engine not supported."; - data_channel_type_ = cricket::DCT_NONE; - data_engine_ = new cricket::RtpDataEngine(); -#endif - } else { - // Even if we have DCT_NONE, we still have a data engine, just - // to make sure it isn't NULL. - data_engine_ = new cricket::RtpDataEngine(); - } - } - - media_client_ = new cricket::MediaSessionClient( - xmpp_client_->jid(), - session_manager_, - media_engine_, - data_engine_, - cricket::DeviceManagerFactory::Create()); - media_client_->SignalCallCreate.connect(this, &CallClient::OnCallCreate); - media_client_->SignalCallDestroy.connect(this, &CallClient::OnCallDestroy); - media_client_->SignalDevicesChange.connect(this, - &CallClient::OnDevicesChange); - media_client_->set_secure(sdes_policy_); - media_client_->set_multisession_enabled(multisession_enabled_); -} - -void CallClient::OnRequestSignaling() { - session_manager_->OnSignalingReady(); -} - -void CallClient::OnSessionCreate(cricket::Session* session, bool initiate) { - session->set_current_protocol(signaling_protocol_); -} - -void CallClient::OnCallCreate(cricket::Call* call) { - call->SignalSessionState.connect(this, &CallClient::OnSessionState); - call->SignalMediaStreamsUpdate.connect( - this, &CallClient::OnMediaStreamsUpdate); -} - -void CallClient::OnSessionState(cricket::Call* call, - cricket::Session* session, - cricket::Session::State state) { - if (state == cricket::Session::STATE_RECEIVEDINITIATE) { - buzz::Jid jid(session->remote_name()); - if (call_ == call && multisession_enabled_) { - // We've received an initiate for an existing call. This is actually a - // new session for that call. - console_->PrintLine("Incoming session from '%s'", jid.Str().c_str()); - AddSession(session); - - cricket::CallOptions options; - options.has_video = call_->has_video(); - options.data_channel_type = data_channel_type_; - call_->AcceptSession(session, options); - - if (call_->has_video() && render_) { - RenderAllStreams(call, session, true); - } - } else { - console_->PrintLine("Incoming call from '%s'", jid.Str().c_str()); - call_ = call; - AddSession(session); - incoming_call_ = true; - if (call->has_video() && render_) { - local_renderer_ = - cricket::VideoRendererFactory::CreateGuiVideoRenderer(160, 100); - } - if (auto_accept_) { - cricket::CallOptions options; - options.has_video = true; - options.data_channel_type = data_channel_type_; - Accept(options); - } - } - } else if (state == cricket::Session::STATE_SENTINITIATE) { - if (call->has_video() && render_) { - local_renderer_ = - cricket::VideoRendererFactory::CreateGuiVideoRenderer(160, 100); - } - console_->PrintLine("calling..."); - } else if (state == cricket::Session::STATE_RECEIVEDACCEPT) { - console_->PrintLine("call answered"); - SetupAcceptedCall(); - } else if (state == cricket::Session::STATE_RECEIVEDREJECT) { - console_->PrintLine("call not answered"); - } else if (state == cricket::Session::STATE_INPROGRESS) { - console_->PrintLine("call in progress"); - call->SignalSpeakerMonitor.connect(this, &CallClient::OnSpeakerChanged); - call->StartSpeakerMonitor(session); - } else if (state == cricket::Session::STATE_RECEIVEDTERMINATE) { - console_->PrintLine("other side terminated"); - TerminateAndRemoveSession(call, session->id()); - } -} - -void CallClient::OnSpeakerChanged(cricket::Call* call, - cricket::Session* session, - const cricket::StreamParams& speaker) { - if (!speaker.has_ssrcs()) { - console_->PrintLine("Session %s has no current speaker.", - session->id().c_str()); - } else if (speaker.id.empty()) { - console_->PrintLine("Session %s speaker change to unknown (%u).", - session->id().c_str(), speaker.first_ssrc()); - } else { - console_->PrintLine("Session %s speaker changed to %s (%u).", - session->id().c_str(), speaker.id.c_str(), - speaker.first_ssrc()); - } -} - -void SetMediaCaps(int media_caps, buzz::PresenceStatus* status) { - status->set_voice_capability((media_caps & cricket::AUDIO_RECV) != 0); - status->set_video_capability((media_caps & cricket::VIDEO_RECV) != 0); - status->set_camera_capability((media_caps & cricket::VIDEO_SEND) != 0); -} - -void SetCaps(int media_caps, buzz::PresenceStatus* status) { - status->set_know_capabilities(true); - status->set_pmuc_capability(true); - SetMediaCaps(media_caps, status); -} - -void SetAvailable(const buzz::Jid& jid, buzz::PresenceStatus* status) { - status->set_jid(jid); - status->set_available(true); - status->set_show(buzz::PresenceStatus::SHOW_ONLINE); -} - -void CallClient::InitPresence() { - presence_push_ = new buzz::PresencePushTask(xmpp_client_, this); - presence_push_->SignalStatusUpdate.connect( - this, &CallClient::OnStatusUpdate); - presence_push_->SignalMucJoined.connect(this, &CallClient::OnMucJoined); - presence_push_->SignalMucLeft.connect(this, &CallClient::OnMucLeft); - presence_push_->SignalMucStatusUpdate.connect( - this, &CallClient::OnMucStatusUpdate); - presence_push_->Start(); - - presence_out_ = new buzz::PresenceOutTask(xmpp_client_); - SetAvailable(xmpp_client_->jid(), &my_status_); - SetCaps(media_client_->GetCapabilities(), &my_status_); - SendStatus(my_status_); - presence_out_->Start(); - - muc_invite_recv_ = new buzz::MucInviteRecvTask(xmpp_client_); - muc_invite_recv_->SignalInviteReceived.connect(this, - &CallClient::OnMucInviteReceived); - muc_invite_recv_->Start(); - - muc_invite_send_ = new buzz::MucInviteSendTask(xmpp_client_); - muc_invite_send_->Start(); - - friend_invite_send_ = new buzz::FriendInviteSendTask(xmpp_client_); - friend_invite_send_->Start(); - - StartXmppPing(); -} - -void CallClient::StartXmppPing() { - buzz::PingTask* ping = new buzz::PingTask( - xmpp_client_, rtc::Thread::Current(), - kPingPeriodMillis, kPingTimeoutMillis); - ping->SignalTimeout.connect(this, &CallClient::OnPingTimeout); - ping->Start(); -} - -void CallClient::OnPingTimeout() { - LOG(LS_WARNING) << "XMPP Ping timeout. Will keep trying..."; - StartXmppPing(); - - // Or should we do this instead? - // Quit(); -} - -void CallClient::SendStatus(const buzz::PresenceStatus& status) { - presence_out_->Send(status); -} - -void CallClient::OnStatusUpdate(const buzz::PresenceStatus& status) { - RosterItem item; - item.jid = status.jid(); - item.show = status.show(); - item.status = status.status(); - - std::string key = item.jid.Str(); - - if (status.available() && status.voice_capability()) { - if (show_roster_messages_) { - console_->PrintLine("Adding to roster: %s", key.c_str()); - } - (*roster_)[key] = item; - // TODO: Make some of these constants. - } else { - if (show_roster_messages_) { - console_->PrintLine("Removing from roster: %s", key.c_str()); - } - RosterMap::iterator iter = roster_->find(key); - if (iter != roster_->end()) - roster_->erase(iter); - } -} - -void CallClient::PrintRoster() { - console_->PrintLine("Roster contains %d callable", roster_->size()); - RosterMap::iterator iter = roster_->begin(); - while (iter != roster_->end()) { - console_->PrintLine("%s - %s", - iter->second.jid.BareJid().Str().c_str(), - DescribeStatus(iter->second.show, iter->second.status)); - iter++; - } -} - -void CallClient::SendChat(const std::string& to, const std::string msg) { - buzz::XmlElement* stanza = new buzz::XmlElement(buzz::QN_MESSAGE); - stanza->AddAttr(buzz::QN_TO, to); - stanza->AddAttr(buzz::QN_ID, rtc::CreateRandomString(16)); - stanza->AddAttr(buzz::QN_TYPE, "chat"); - buzz::XmlElement* body = new buzz::XmlElement(buzz::QN_BODY); - body->SetBodyText(msg); - stanza->AddElement(body); - - xmpp_client_->SendStanza(stanza); - delete stanza; -} - -void CallClient::SendData(const std::string& streamid, - const std::string& text) { - // TODO(mylesj): Support sending data over sessions other than the first. - cricket::Session* session = GetFirstSession(); - if (!call_ || !session) { - console_->PrintLine("Must be in a call to send data."); - return; - } - if (!call_->has_data()) { - console_->PrintLine("This call doesn't have a data channel."); - return; - } - - const cricket::DataContentDescription* data = - cricket::GetFirstDataContentDescription(session->local_description()); - if (!data) { - console_->PrintLine("This call doesn't have a data content."); - return; - } - - const cricket::StreamParams* stream = - cricket::GetStreamByIds(data->streams(), "", streamid) - if (!stream) { - LOG(LS_WARNING) << "Could not send data: no such stream: " - << streamid << "."; - return; - } - - cricket::SendDataParams params; - params.ssrc = stream->first_ssrc(); - rtc::Buffer payload(text.data(), text.length()); - cricket::SendDataResult result; - bool sent = call_->SendData(session, params, payload, &result); - if (!sent) { - if (result == cricket::SDR_BLOCK) { - LOG(LS_WARNING) << "Could not send data because it would block."; - } else { - LOG(LS_WARNING) << "Could not send data for unknown reason."; - } - } -} - -void CallClient::InviteFriend(const std::string& name) { - buzz::Jid jid(name); - if (!jid.IsValid() || jid.node() == "") { - console_->PrintLine("Invalid JID. JIDs should be in the form user@domain."); - return; - } - // Note: for some reason the Buzz backend does not forward our presence - // subscription requests to the end user when that user is another call - // client as opposed to a Smurf user. Thus, in that scenario, you must - // run the friend command as the other user too to create the linkage - // (and you won't be notified to do so). - friend_invite_send_->Send(jid); - console_->PrintLine("Requesting to befriend %s.", name.c_str()); -} - -bool CallClient::FindJid(const std::string& name, buzz::Jid* found_jid, - cricket::CallOptions* options) { - bool found = false; - options->is_muc = false; - buzz::Jid callto_jid(name); - if (name.length() == 0 && mucs_.size() > 0) { - // if no name, and in a MUC, establish audio with the MUC - *found_jid = mucs_.begin()->first; - found = true; - options->is_muc = true; - } else if (name[0] == '+') { - // if the first character is a +, assume it's a phone number - *found_jid = callto_jid; - found = true; - } else { - // otherwise, it's a friend - for (RosterMap::iterator iter = roster_->begin(); - iter != roster_->end(); ++iter) { - if (iter->second.jid.BareEquals(callto_jid)) { - found = true; - *found_jid = iter->second.jid; - break; - } - } - - if (!found) { - if (mucs_.count(callto_jid) == 1 && - mucs_[callto_jid]->state() == buzz::Muc::MUC_JOINED) { - found = true; - *found_jid = callto_jid; - options->is_muc = true; - } - } - } - - if (found) { - console_->PrintLine("Found %s '%s'", - options->is_muc ? "room" : "online friend", - found_jid->Str().c_str()); - } else { - console_->PrintLine("Could not find online friend '%s'", name.c_str()); - } - - return found; -} - -void CallClient::OnDataReceived(cricket::Call*, - const cricket::ReceiveDataParams& params, - const rtc::Buffer& payload) { - // TODO(mylesj): Support receiving data on sessions other than the first. - cricket::Session* session = GetFirstSession(); - if (!session) - return; - - const std::vector* data_streams = - call_->GetDataRecvStreams(session); - const cricket::StreamParams* stream = - data_streams ? GetStreamBySsrc(*data_streams, params.ssrc) : nullptr; - std::string text(payload.data(), payload.length()); - if (stream) { - console_->PrintLine( - "Received data from '%s' on stream '%s' (ssrc=%u): %s", - stream->groupid.c_str(), stream->id.c_str(), - params->ssrc, text.c_str()); - } else { - console_->PrintLine( - "Received data (ssrc=%u): %s", - params.ssrc, text.c_str()); - } -} - -bool CallClient::PlaceCall(const std::string& name, - cricket::CallOptions options) { - buzz::Jid jid; - if (!FindJid(name, &jid, &options)) - return false; - - if (!call_) { - call_ = media_client_->CreateCall(); - AddSession(call_->InitiateSession(jid, media_client_->jid(), options)); - } - media_client_->SetFocus(call_); - if (call_->has_video() && render_ && !options.is_muc) { - // TODO(pthatcher): Hookup local_render_ to the local capturer. - } - if (options.is_muc) { - const std::string& nick = mucs_[jid]->local_jid().resource(); - hangout_pubsub_client_ = - new buzz::HangoutPubSubClient(xmpp_client_, jid, nick); - hangout_pubsub_client_->SignalPresenterStateChange.connect( - this, &CallClient::OnPresenterStateChange); - hangout_pubsub_client_->SignalAudioMuteStateChange.connect( - this, &CallClient::OnAudioMuteStateChange); - hangout_pubsub_client_->SignalRecordingStateChange.connect( - this, &CallClient::OnRecordingStateChange); - hangout_pubsub_client_->SignalRemoteMute.connect( - this, &CallClient::OnRemoteMuted); - hangout_pubsub_client_->SignalMediaBlock.connect( - this, &CallClient::OnMediaBlocked); - hangout_pubsub_client_->SignalRequestError.connect( - this, &CallClient::OnHangoutRequestError); - hangout_pubsub_client_->SignalPublishAudioMuteError.connect( - this, &CallClient::OnHangoutPublishAudioMuteError); - hangout_pubsub_client_->SignalPublishPresenterError.connect( - this, &CallClient::OnHangoutPublishPresenterError); - hangout_pubsub_client_->SignalPublishRecordingError.connect( - this, &CallClient::OnHangoutPublishRecordingError); - hangout_pubsub_client_->SignalRemoteMuteError.connect( - this, &CallClient::OnHangoutRemoteMuteError); - hangout_pubsub_client_->RequestAll(); - } - - return true; -} - -bool CallClient::InitiateAdditionalSession(const std::string& name, - cricket::CallOptions options) { - // Can't add a session if there is no call yet. - if (!call_) - return false; - - buzz::Jid jid; - if (!FindJid(name, &jid, &options)) - return false; - - std::vector& call_sessions = sessions_[call_->id()]; - call_sessions.push_back( - call_->InitiateSession(jid, - buzz::Jid(call_sessions[0]->remote_name()), - options)); - - return true; -} - -void CallClient::TerminateAndRemoveSession(cricket::Call* call, - const std::string& id) { - std::vector& call_sessions = sessions_[call->id()]; - for (std::vector::iterator iter = call_sessions.begin(); - iter != call_sessions.end(); ++iter) { - if ((*iter)->id() == id) { - RenderAllStreams(call, *iter, false); - call_->TerminateSession(*iter); - call_sessions.erase(iter); - break; - } - } -} - -void CallClient::PrintCalls() { - const std::map& calls = media_client_->calls(); - for (std::map::const_iterator i = calls.begin(); - i != calls.end(); ++i) { - console_->PrintLine("Call (id:%d), is %s", - i->first, - i->second == call_ ? "active" : "on hold"); - std::vector& sessions = sessions_[call_->id()]; - for (std::vector::const_iterator j = sessions.begin(); - j != sessions.end(); ++j) { - console_->PrintLine("|--Session (id:%s), to %s", (*j)->id().c_str(), - (*j)->remote_name().c_str()); - - std::vector::const_iterator k; - const std::vector* streams = - i->second->GetAudioRecvStreams(*j); - if (streams) - for (k = streams->begin(); k != streams->end(); ++k) { - console_->PrintLine("|----Audio Stream: %s", k->ToString().c_str()); - } - streams = i->second->GetVideoRecvStreams(*j); - if (streams) - for (k = streams->begin(); k != streams->end(); ++k) { - console_->PrintLine("|----Video Stream: %s", k->ToString().c_str()); - } - streams = i->second->GetDataRecvStreams(*j); - if (streams) - for (k = streams->begin(); k != streams->end(); ++k) { - console_->PrintLine("|----Data Stream: %s", k->ToString().c_str()); - } - } - } -} - -void CallClient::SwitchToCall(uint32 call_id) { - const std::map& calls = media_client_->calls(); - std::map::const_iterator call_iter = - calls.find(call_id); - if (call_iter != calls.end()) { - media_client_->SetFocus(call_iter->second); - call_ = call_iter->second; - } else { - console_->PrintLine("Unable to find call: %d", call_id); - } -} - -void CallClient::OnPresenterStateChange( - const std::string& nick, bool was_presenting, bool is_presenting) { - if (!was_presenting && is_presenting) { - console_->PrintLine("%s now presenting.", nick.c_str()); - } else if (was_presenting && !is_presenting) { - console_->PrintLine("%s no longer presenting.", nick.c_str()); - } else if (was_presenting && is_presenting) { - console_->PrintLine("%s still presenting.", nick.c_str()); - } else if (!was_presenting && !is_presenting) { - console_->PrintLine("%s still not presenting.", nick.c_str()); - } -} - -void CallClient::OnAudioMuteStateChange( - const std::string& nick, bool was_muted, bool is_muted) { - if (!was_muted && is_muted) { - console_->PrintLine("%s now muted.", nick.c_str()); - } else if (was_muted && !is_muted) { - console_->PrintLine("%s no longer muted.", nick.c_str()); - } -} - -void CallClient::OnRecordingStateChange( - const std::string& nick, bool was_recording, bool is_recording) { - if (!was_recording && is_recording) { - console_->PrintLine("%s now recording.", nick.c_str()); - } else if (was_recording && !is_recording) { - console_->PrintLine("%s no longer recording.", nick.c_str()); - } -} - -void CallClient::OnRemoteMuted(const std::string& mutee_nick, - const std::string& muter_nick, - bool should_mute_locally) { - if (should_mute_locally) { - call_->Mute(true); - console_->PrintLine("Remote muted by %s.", muter_nick.c_str()); - } else { - console_->PrintLine("%s remote muted by %s.", - mutee_nick.c_str(), muter_nick.c_str()); - } -} - -void CallClient::OnMediaBlocked(const std::string& blockee_nick, - const std::string& blocker_nick) { - console_->PrintLine("%s blocked by %s.", - blockee_nick.c_str(), blocker_nick.c_str()); -} - -void CallClient::OnHangoutRequestError(const std::string& node, - const buzz::XmlElement* stanza) { - console_->PrintLine("Failed request pub sub items for node %s.", - node.c_str()); -} - -void CallClient::OnHangoutPublishAudioMuteError( - const std::string& task_id, const buzz::XmlElement* stanza) { - console_->PrintLine("Failed to publish audio mute state."); -} - -void CallClient::OnHangoutPublishPresenterError( - const std::string& task_id, const buzz::XmlElement* stanza) { - console_->PrintLine("Failed to publish presenting state."); -} - -void CallClient::OnHangoutPublishRecordingError( - const std::string& task_id, const buzz::XmlElement* stanza) { - console_->PrintLine("Failed to publish recording state."); -} - -void CallClient::OnHangoutRemoteMuteError(const std::string& task_id, - const std::string& mutee_nick, - const buzz::XmlElement* stanza) { - console_->PrintLine("Failed to remote mute."); -} - -void CallClient::Accept(const cricket::CallOptions& options) { - ASSERT(call_ && incoming_call_); - ASSERT(sessions_[call_->id()].size() == 1); - cricket::Session* session = GetFirstSession(); - call_->AcceptSession(session, options); - media_client_->SetFocus(call_); - if (call_->has_video() && render_) { - // TODO(pthatcher): Hookup local_render_ to the local capturer. - RenderAllStreams(call_, session, true); - } - SetupAcceptedCall(); - incoming_call_ = false; -} - -void CallClient::SetupAcceptedCall() { - if (call_->has_data()) { - call_->SignalDataReceived.connect(this, &CallClient::OnDataReceived); - } -} - -void CallClient::Reject() { - ASSERT(call_ && incoming_call_); - call_->RejectSession(call_->sessions()[0]); - incoming_call_ = false; -} - -void CallClient::Quit() { - rtc::Thread::Current()->Quit(); -} - -void CallClient::SetNick(const std::string& muc_nick) { - my_status_.set_nick(muc_nick); - - // TODO: We might want to re-send presence, but right - // now, it appears to be ignored by the MUC. - // - // presence_out_->Send(my_status_); for (MucMap::const_iterator itr - // = mucs_.begin(); itr != mucs_.end(); ++itr) { - // presence_out_->SendDirected(itr->second->local_jid(), - // my_status_); } - - console_->PrintLine("Nick set to '%s'.", muc_nick.c_str()); -} - -void CallClient::LookupAndJoinMuc(const std::string& room_name) { - // The room_name can't be empty for lookup task. - if (room_name.empty()) { - console_->PrintLine("Please provide a room name or room jid."); - return; - } - - std::string room = room_name; - std::string domain = xmpp_client_->jid().domain(); - if (room_name.find("@") != std::string::npos) { - // Assume the room_name is a fully qualified room name. - // We'll find the room name string and domain name string from it. - room = room_name.substr(0, room_name.find("@")); - domain = room_name.substr(room_name.find("@") + 1); - } - - buzz::MucRoomLookupTask* lookup_query_task = - buzz::MucRoomLookupTask::CreateLookupTaskForRoomName( - xmpp_client_, buzz::Jid(buzz::STR_GOOGLE_MUC_LOOKUP_JID), room, - domain); - lookup_query_task->SignalResult.connect(this, - &CallClient::OnRoomLookupResponse); - lookup_query_task->SignalError.connect(this, - &CallClient::OnRoomLookupError); - lookup_query_task->Start(); -} - -void CallClient::JoinMuc(const std::string& room_jid_str) { - if (room_jid_str.empty()) { - buzz::Jid room_jid = GenerateRandomMucJid(); - console_->PrintLine("Generated a random room jid: %s", - room_jid.Str().c_str()); - JoinMuc(room_jid); - } else { - JoinMuc(buzz::Jid(room_jid_str)); - } -} - -void CallClient::JoinMuc(const buzz::Jid& room_jid) { - if (!room_jid.IsValid()) { - console_->PrintLine("Unable to make valid muc endpoint for %s", - room_jid.Str().c_str()); - return; - } - - std::string room_nick = room_jid.resource(); - if (room_nick.empty()) { - room_nick = (xmpp_client_->jid().node() - + "_" + xmpp_client_->jid().resource()); - } - - MucMap::iterator elem = mucs_.find(room_jid); - if (elem != mucs_.end()) { - console_->PrintLine("This MUC already exists."); - return; - } - - buzz::Muc* muc = new buzz::Muc(room_jid.BareJid(), room_nick); - mucs_[muc->jid()] = muc; - presence_out_->SendDirected(muc->local_jid(), my_status_); -} - -void CallClient::OnRoomLookupResponse(buzz::MucRoomLookupTask* task, - const buzz::MucRoomInfo& room) { - // The server requires the room be "configured" before being used. - // We only need to configure it if we create it, but rooms are - // auto-created at lookup, so there's currently no way to know if we - // created it. So, we configure it every time, just in case. - // Luckily, it appears to be safe to configure a room that's already - // configured. Our current flow is: - // 1. Lookup/auto-create - // 2. Configure - // 3. Join - // TODO: In the future, once the server supports it, we - // should: - // 1. Lookup - // 2. Create and Configure if necessary - // 3. Join - std::vector room_features; - room_features.push_back(buzz::STR_MUC_ROOM_FEATURE_ENTERPRISE); - buzz::MucRoomConfigTask* room_config_task = new buzz::MucRoomConfigTask( - xmpp_client_, room.jid, room.full_name(), room_features); - room_config_task->SignalResult.connect(this, - &CallClient::OnRoomConfigResult); - room_config_task->SignalError.connect(this, - &CallClient::OnRoomConfigError); - room_config_task->Start(); -} - -void CallClient::OnRoomLookupError(buzz::IqTask* task, - const buzz::XmlElement* stanza) { - if (stanza == NULL) { - console_->PrintLine("Room lookup failed."); - } else { - console_->PrintLine("Room lookup error: ", stanza->Str().c_str()); - } -} - -void CallClient::OnRoomConfigResult(buzz::MucRoomConfigTask* task) { - JoinMuc(task->room_jid()); -} - -void CallClient::OnRoomConfigError(buzz::IqTask* task, - const buzz::XmlElement* stanza) { - console_->PrintLine("Room config failed."); - // We join the muc anyway, because if the room is already - // configured, the configure will fail, but we still want to join. - // Idealy, we'd know why the room config failed and only do this on - // "already configured" errors. But right now all we get back is - // "not-allowed". - buzz::MucRoomConfigTask* config_task = - static_cast(task); - JoinMuc(config_task->room_jid()); -} - -void CallClient::OnMucInviteReceived(const buzz::Jid& inviter, - const buzz::Jid& room, - const std::vector& avail) { - - console_->PrintLine("Invited to join %s by %s.", room.Str().c_str(), - inviter.Str().c_str()); - console_->PrintLine("Available media:"); - if (avail.size() > 0) { - for (std::vector::const_iterator i = - avail.begin(); - i != avail.end(); - ++i) { - console_->PrintLine(" %s, %s", - buzz::AvailableMediaEntry::TypeAsString(i->type), - buzz::AvailableMediaEntry::StatusAsString(i->status)); - } - } else { - console_->PrintLine(" None"); - } - // We automatically join the room. - JoinMuc(room); -} - -void CallClient::OnMucJoined(const buzz::Jid& endpoint) { - MucMap::iterator elem = mucs_.find(endpoint); - ASSERT(elem != mucs_.end() && - elem->second->state() == buzz::Muc::MUC_JOINING); - - buzz::Muc* muc = elem->second; - muc->set_state(buzz::Muc::MUC_JOINED); - console_->PrintLine("Joined \"%s\"", muc->jid().Str().c_str()); -} - -void CallClient::OnMucStatusUpdate(const buzz::Jid& jid, - const buzz::MucPresenceStatus& status) { - - // Look up this muc. - MucMap::iterator elem = mucs_.find(jid); - ASSERT(elem != mucs_.end()); - - buzz::Muc* muc = elem->second; - - if (status.jid().IsBare() || status.jid() == muc->local_jid()) { - // We are only interested in status about other users. - return; - } - - if (status.available()) { - muc->members()[status.jid().resource()] = status; - } else { - muc->members().erase(status.jid().resource()); - } -} - -bool CallClient::InMuc() { - const buzz::Jid* muc_jid = FirstMucJid(); - if (!muc_jid) return false; - return muc_jid->IsValid(); -} - -const buzz::Jid* CallClient::FirstMucJid() { - if (mucs_.empty()) return NULL; - return &(mucs_.begin()->first); -} - -void CallClient::LeaveMuc(const std::string& room) { - buzz::Jid room_jid; - const buzz::Jid* muc_jid = FirstMucJid(); - if (room.length() > 0) { - room_jid = buzz::Jid(room); - } else if (mucs_.size() > 0) { - // leave the first MUC if no JID specified - if (muc_jid) { - room_jid = *(muc_jid); - } - } - - if (!room_jid.IsValid()) { - console_->PrintLine("Invalid MUC JID."); - return; - } - - MucMap::iterator elem = mucs_.find(room_jid); - if (elem == mucs_.end()) { - console_->PrintLine("No such MUC."); - return; - } - - buzz::Muc* muc = elem->second; - muc->set_state(buzz::Muc::MUC_LEAVING); - - buzz::PresenceStatus status; - status.set_jid(my_status_.jid()); - status.set_available(false); - status.set_priority(0); - presence_out_->SendDirected(muc->local_jid(), status); -} - -void CallClient::OnMucLeft(const buzz::Jid& endpoint, int error) { - // We could be kicked from a room from any state. We would hope this - // happens While in the MUC_LEAVING state - MucMap::iterator elem = mucs_.find(endpoint); - if (elem == mucs_.end()) - return; - - buzz::Muc* muc = elem->second; - if (muc->state() == buzz::Muc::MUC_JOINING) { - console_->PrintLine("Failed to join \"%s\", code=%d", - muc->jid().Str().c_str(), error); - } else if (muc->state() == buzz::Muc::MUC_JOINED) { - console_->PrintLine("Kicked from \"%s\"", - muc->jid().Str().c_str()); - } - - delete muc; - mucs_.erase(elem); -} - -void CallClient::InviteToMuc(const std::string& given_user, - const std::string& room) { - std::string user = given_user; - - // First find the room. - const buzz::Muc* found_muc; - if (room.length() == 0) { - if (mucs_.size() == 0) { - console_->PrintLine("Not in a room yet; can't invite."); - return; - } - // Invite to the first muc - found_muc = mucs_.begin()->second; - } else { - MucMap::iterator elem = mucs_.find(buzz::Jid(room)); - if (elem == mucs_.end()) { - console_->PrintLine("Not in room %s.", room.c_str()); - return; - } - found_muc = elem->second; - } - - buzz::Jid invite_to = found_muc->jid(); - - // Now find the user. We invite all of their resources. - bool found_user = false; - buzz::Jid user_jid(user); - for (RosterMap::iterator iter = roster_->begin(); - iter != roster_->end(); ++iter) { - if (iter->second.jid.BareEquals(user_jid)) { - buzz::Jid invitee = iter->second.jid; - muc_invite_send_->Send(invite_to, invitee); - found_user = true; - } - } - if (!found_user) { - buzz::Jid invitee = user_jid; - muc_invite_send_->Send(invite_to, invitee); - } -} - -void CallClient::GetDevices() { - std::vector names; - media_client_->GetAudioInputDevices(&names); - console_->PrintLine("Audio input devices:"); - PrintDevices(names); - media_client_->GetAudioOutputDevices(&names); - console_->PrintLine("Audio output devices:"); - PrintDevices(names); - media_client_->GetVideoCaptureDevices(&names); - console_->PrintLine("Video capture devices:"); - PrintDevices(names); -} - -void CallClient::PrintDevices(const std::vector& names) { - for (size_t i = 0; i < names.size(); ++i) { - console_->PrintLine("%d: %s", static_cast(i), names[i].c_str()); - } -} - -void CallClient::OnDevicesChange() { - console_->PrintLine("Devices changed."); - SetMediaCaps(media_client_->GetCapabilities(), &my_status_); - SendStatus(my_status_); -} - -void CallClient::SetVolume(const std::string& level) { - media_client_->SetOutputVolume(strtol(level.c_str(), NULL, 10)); -} - -void CallClient::OnMediaStreamsUpdate(cricket::Call* call, - cricket::Session* session, - const cricket::MediaStreams& added, - const cricket::MediaStreams& removed) { - if (call && call->has_video()) { - for (std::vector::const_iterator - it = removed.video().begin(); it != removed.video().end(); ++it) { - RemoveStaticRenderedView(it->first_ssrc()); - } - - if (render_) { - RenderStreams(call, session, added.video(), true); - } - SendViewRequest(call, session); - } -} - -void CallClient::RenderAllStreams(cricket::Call* call, - cricket::Session* session, - bool enable) { - const std::vector* video_streams = - call->GetVideoRecvStreams(session); - if (video_streams) { - RenderStreams(call, session, *video_streams, enable); - } -} - -void CallClient::RenderStreams( - cricket::Call* call, - cricket::Session* session, - const std::vector& video_streams, - bool enable) { - std::vector::const_iterator stream; - for (stream = video_streams.begin(); stream != video_streams.end(); - ++stream) { - RenderStream(call, session, *stream, enable); - } -} - -void CallClient::RenderStream(cricket::Call* call, - cricket::Session* session, - const cricket::StreamParams& stream, - bool enable) { - if (!stream.has_ssrcs()) { - // Nothing to see here; move along. - return; - } - - uint32 ssrc = stream.first_ssrc(); - StaticRenderedViews::iterator iter = - static_rendered_views_.find(std::make_pair(session, ssrc)); - if (enable) { - if (iter == static_rendered_views_.end()) { - // TODO(pthatcher): Make dimensions and positions more configurable. - int offset = (50 * static_views_accumulated_count_) % 300; - AddStaticRenderedView(session, ssrc, 640, 400, 30, - offset, offset); - // Should have it now. - iter = static_rendered_views_.find(std::make_pair(session, ssrc)); - } - call->SetVideoRenderer(session, ssrc, iter->second.renderer); - } else { - if (iter != static_rendered_views_.end()) { - call->SetVideoRenderer(session, ssrc, NULL); - RemoveStaticRenderedView(ssrc); - } - } -} - -// TODO: Would these methods to add and remove views make -// more sense in call.cc? Would other clients use them? -void CallClient::AddStaticRenderedView( - cricket::Session* session, - uint32 ssrc, int width, int height, int framerate, - int x_offset, int y_offset) { - StaticRenderedView rendered_view( - cricket::StaticVideoView( - cricket::StreamSelector(ssrc), width, height, framerate), - cricket::VideoRendererFactory::CreateGuiVideoRenderer( - x_offset, y_offset)); - rendered_view.renderer->SetSize(width, height, 0); - static_rendered_views_.insert(std::make_pair(std::make_pair(session, ssrc), - rendered_view)); - ++static_views_accumulated_count_; - console_->PrintLine("Added renderer for ssrc %d", ssrc); -} - -bool CallClient::RemoveStaticRenderedView(uint32 ssrc) { - for (StaticRenderedViews::iterator it = static_rendered_views_.begin(); - it != static_rendered_views_.end(); ++it) { - if (it->second.view.selector.ssrc == ssrc) { - delete it->second.renderer; - static_rendered_views_.erase(it); - console_->PrintLine("Removed renderer for ssrc %d", ssrc); - return true; - } - } - return false; -} - -void CallClient::RemoveCallsStaticRenderedViews(cricket::Call* call) { - std::vector& sessions = sessions_[call->id()]; - std::set call_sessions(sessions.begin(), sessions.end()); - for (StaticRenderedViews::iterator it = static_rendered_views_.begin(); - it != static_rendered_views_.end(); ) { - if (call_sessions.find(it->first.first) != call_sessions.end()) { - delete it->second.renderer; - static_rendered_views_.erase(it++); - } else { - ++it; - } - } -} - -void CallClient::SendViewRequest(cricket::Call* call, - cricket::Session* session) { - cricket::ViewRequest request; - for (StaticRenderedViews::iterator it = static_rendered_views_.begin(); - it != static_rendered_views_.end(); ++it) { - if (it->first.first == session) { - request.static_video_views.push_back(it->second.view); - } - } - call->SendViewRequest(session, request); -} - -buzz::Jid CallClient::GenerateRandomMucJid() { - // Generate a GUID of the form XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX, - // for an eventual JID of private-chat-@groupchat.google.com. - char guid[37], guid_room[256]; - for (size_t i = 0; i < ARRAY_SIZE(guid) - 1;) { - if (i == 8 || i == 13 || i == 18 || i == 23) { - guid[i++] = '-'; - } else { - sprintf(guid + i, "%04x", rand()); - i += 4; - } - } - - rtc::sprintfn(guid_room, - ARRAY_SIZE(guid_room), - "private-chat-%s@%s", - guid, - pmuc_domain_.c_str()); - return buzz::Jid(guid_room); -} - -bool CallClient::SelectFirstDesktopScreencastId( - cricket::ScreencastId* screencastid) { - if (!rtc::WindowPickerFactory::IsSupported()) { - LOG(LS_WARNING) << "Window picker not suported on this OS."; - return false; - } - - rtc::WindowPicker* picker = - rtc::WindowPickerFactory::CreateWindowPicker(); - if (!picker) { - LOG(LS_WARNING) << "Could not create a window picker."; - return false; - } - - rtc::DesktopDescriptionList desktops; - if (!picker->GetDesktopList(&desktops) || desktops.empty()) { - LOG(LS_WARNING) << "Could not get a list of desktops."; - return false; - } - - *screencastid = cricket::ScreencastId(desktops[0].id()); - return true; -} - -void CallClient::PrintStats() const { - const cricket::VoiceMediaInfo& vmi = call_->last_voice_media_info(); - - for (std::vector::const_iterator it = - vmi.senders.begin(); it != vmi.senders.end(); ++it) { - console_->PrintLine("Sender: ssrc=%u codec='%s' bytes=%d packets=%d " - "rtt=%d jitter=%d", - it->ssrc(), it->codec_name.c_str(), it->bytes_sent, - it->packets_sent, it->rtt_ms, it->jitter_ms); - } - - for (std::vector::const_iterator it = - vmi.receivers.begin(); it != vmi.receivers.end(); ++it) { - console_->PrintLine("Receiver: ssrc=%u bytes=%d packets=%d " - "jitter=%d loss=%.2f", - it->ssrc(), it->bytes_rcvd, it->packets_rcvd, - it->jitter_ms, it->fraction_lost); - } -} diff --git a/webrtc/libjingle/examples/call/callclient.h b/webrtc/libjingle/examples/call/callclient.h deleted file mode 100644 index 70d3778a6..000000000 --- a/webrtc/libjingle/examples/call/callclient.h +++ /dev/null @@ -1,352 +0,0 @@ -/* - * 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. - */ - -#ifndef WEBRTC_LIBJINGLE_EXAMPLES_CALL_CALLCLIENT_H_ -#define WEBRTC_LIBJINGLE_EXAMPLES_CALL_CALLCLIENT_H_ - -#include -#include -#include - -#include "talk/examples/call/console.h" -#include "talk/media/base/mediachannel.h" -#include "webrtc/base/scoped_ptr.h" -#include "webrtc/base/sslidentity.h" -#include "webrtc/libjingle/session/media/mediamessages.h" -#include "webrtc/libjingle/session/media/mediasessionclient.h" -#include "webrtc/libjingle/xmpp/hangoutpubsubclient.h" -#include "webrtc/libjingle/xmpp/presencestatus.h" -#include "webrtc/libjingle/xmpp/xmppclient.h" -#include "webrtc/p2p/base/session.h" - -namespace buzz { -class PresencePushTask; -class PresenceOutTask; -class MucInviteRecvTask; -class MucInviteSendTask; -class FriendInviteSendTask; -class DiscoInfoQueryTask; -class Muc; -class PresenceStatus; -class IqTask; -class MucRoomConfigTask; -class MucRoomLookupTask; -class MucPresenceStatus; -class XmlElement; -class HangoutPubSubClient; -struct AvailableMediaEntry; -struct MucRoomInfo; -} // namespace buzz - -namespace rtc { -class Thread; -class NetworkManager; -} // namespace rtc - -namespace cricket { -class PortAllocator; -class MediaEngineInterface; -class MediaSessionClient; -class Call; -class SessionManagerTask; -struct CallOptions; -struct MediaStreams; -struct StreamParams; -} // namespace cricket - -struct RosterItem { - buzz::Jid jid; - buzz::PresenceStatus::Show show; - std::string status; -}; - -struct StaticRenderedView { - StaticRenderedView(const cricket::StaticVideoView& view, - cricket::VideoRenderer* renderer) : - view(view), - renderer(renderer) { - } - - cricket::StaticVideoView view; - cricket::VideoRenderer* renderer; -}; - -// Maintain a mapping of (session, ssrc) to rendered view. -typedef std::map, - StaticRenderedView> StaticRenderedViews; - -class CallClient: public sigslot::has_slots<> { - public: - CallClient(buzz::XmppClient* xmpp_client, - const std::string& caps_node, - const std::string& version); - ~CallClient(); - - cricket::MediaSessionClient* media_client() const { return media_client_; } - void SetMediaEngine(cricket::MediaEngineInterface* media_engine) { - media_engine_ = media_engine; - } - void SetAutoAccept(bool auto_accept) { - auto_accept_ = auto_accept; - } - void SetPmucDomain(const std::string &pmuc_domain) { - pmuc_domain_ = pmuc_domain; - } - void SetRender(bool render) { - render_ = render; - } - void SetDataChannelType(cricket::DataChannelType data_channel_type) { - data_channel_type_ = data_channel_type; - } - void SetMultiSessionEnabled(bool multisession_enabled) { - multisession_enabled_ = multisession_enabled; - } - void SetConsole(Console *console) { - console_ = console; - } - void SetPriority(int priority) { - my_status_.set_priority(priority); - } - void SendStatus() { - SendStatus(my_status_); - } - void SendStatus(const buzz::PresenceStatus& status); - - void ParseLine(const std::string &str); - - void SendChat(const std::string& to, const std::string msg); - void SendData(const std::string& stream_name, - const std::string& text); - void InviteFriend(const std::string& user); - void JoinMuc(const buzz::Jid& room_jid); - void JoinMuc(const std::string& room_jid_str); - void LookupAndJoinMuc(const std::string& room_name); - void InviteToMuc(const std::string& user, const std::string& room); - bool InMuc(); - const buzz::Jid* FirstMucJid(); - void LeaveMuc(const std::string& room); - void SetNick(const std::string& muc_nick); - void SetPortAllocatorFlags(uint32 flags) { portallocator_flags_ = flags; } - void SetAllowLocalIps(bool allow_local_ips) { - allow_local_ips_ = allow_local_ips; - } - - void SetSignalingProtocol(cricket::SignalingProtocol protocol) { - signaling_protocol_ = protocol; - } - void SetTransportProtocol(cricket::TransportProtocol protocol) { - transport_protocol_ = protocol; - } - void SetSecurePolicy(cricket::SecurePolicy sdes_policy, - cricket::SecurePolicy dtls_policy) { - sdes_policy_ = sdes_policy; - dtls_policy_ = dtls_policy; - } - void SetSslIdentity(rtc::SSLIdentity* identity) { - ssl_identity_.reset(identity); - } - - typedef std::map MucMap; - - const MucMap& mucs() const { - return mucs_; - } - - void SetShowRosterMessages(bool show_roster_messages) { - show_roster_messages_ = show_roster_messages; - } - - private: - void AddStream(uint32 audio_src_id, uint32 video_src_id); - void RemoveStream(uint32 audio_src_id, uint32 video_src_id); - void OnStateChange(buzz::XmppEngine::State state); - - void InitMedia(); - void InitPresence(); - void StartXmppPing(); - void OnPingTimeout(); - void OnRequestSignaling(); - void OnSessionCreate(cricket::Session* session, bool initiate); - void OnCallCreate(cricket::Call* call); - void OnCallDestroy(cricket::Call* call); - void OnSessionState(cricket::Call* call, - cricket::Session* session, - cricket::Session::State state); - void OnStatusUpdate(const buzz::PresenceStatus& status); - void OnMucInviteReceived(const buzz::Jid& inviter, const buzz::Jid& room, - const std::vector& avail); - void OnMucJoined(const buzz::Jid& endpoint); - void OnMucStatusUpdate(const buzz::Jid& jid, - const buzz::MucPresenceStatus& status); - void OnMucLeft(const buzz::Jid& endpoint, int error); - void OnPresenterStateChange(const std::string& nick, - bool was_presenting, bool is_presenting); - void OnAudioMuteStateChange(const std::string& nick, - bool was_muted, bool is_muted); - void OnRecordingStateChange(const std::string& nick, - bool was_recording, bool is_recording); - void OnRemoteMuted(const std::string& mutee_nick, - const std::string& muter_nick, - bool should_mute_locally); - void OnMediaBlocked(const std::string& blockee_nick, - const std::string& blocker_nick); - void OnHangoutRequestError(const std::string& node, - const buzz::XmlElement* stanza); - void OnHangoutPublishAudioMuteError(const std::string& task_id, - const buzz::XmlElement* stanza); - void OnHangoutPublishPresenterError(const std::string& task_id, - const buzz::XmlElement* stanza); - void OnHangoutPublishRecordingError(const std::string& task_id, - const buzz::XmlElement* stanza); - void OnHangoutRemoteMuteError(const std::string& task_id, - const std::string& mutee_nick, - const buzz::XmlElement* stanza); - void OnDevicesChange(); - void OnMediaStreamsUpdate(cricket::Call* call, - cricket::Session* session, - const cricket::MediaStreams& added, - const cricket::MediaStreams& removed); - void OnSpeakerChanged(cricket::Call* call, - cricket::Session* session, - const cricket::StreamParams& speaker_stream); - void OnRoomLookupResponse(buzz::MucRoomLookupTask* task, - const buzz::MucRoomInfo& room_info); - void OnRoomLookupError(buzz::IqTask* task, - const buzz::XmlElement* stanza); - void OnRoomConfigResult(buzz::MucRoomConfigTask* task); - void OnRoomConfigError(buzz::IqTask* task, - const buzz::XmlElement* stanza); - void OnDataReceived(cricket::Call*, - const cricket::ReceiveDataParams& params, - const rtc::Buffer& payload); - buzz::Jid GenerateRandomMucJid(); - - // Depending on |enable|, render (or don't) all the streams in |session|. - void RenderAllStreams(cricket::Call* call, - cricket::Session* session, - bool enable); - - // Depending on |enable|, render (or don't) the streams in |video_streams|. - void RenderStreams(cricket::Call* call, - cricket::Session* session, - const std::vector& video_streams, - bool enable); - - // Depending on |enable|, render (or don't) the supplied |stream|. - void RenderStream(cricket::Call* call, - cricket::Session* session, - const cricket::StreamParams& stream, - bool enable); - void AddStaticRenderedView( - cricket::Session* session, - uint32 ssrc, int width, int height, int framerate, - int x_offset, int y_offset); - bool RemoveStaticRenderedView(uint32 ssrc); - void RemoveCallsStaticRenderedViews(cricket::Call* call); - void SendViewRequest(cricket::Call* call, cricket::Session* session); - bool SelectFirstDesktopScreencastId(cricket::ScreencastId* screencastid); - - static const std::string strerror(buzz::XmppEngine::Error err); - - void PrintRoster(); - bool FindJid(const std::string& name, - buzz::Jid* found_jid, - cricket::CallOptions* options); - bool PlaceCall(const std::string& name, cricket::CallOptions options); - bool InitiateAdditionalSession(const std::string& name, - cricket::CallOptions options); - void TerminateAndRemoveSession(cricket::Call* call, const std::string& id); - void PrintCalls(); - void SwitchToCall(uint32 call_id); - void Accept(const cricket::CallOptions& options); - void Reject(); - void Quit(); - - void GetDevices(); - void PrintDevices(const std::vector& names); - - void SetVolume(const std::string& level); - - cricket::Session* GetFirstSession() { return sessions_[call_->id()][0]; } - void AddSession(cricket::Session* session) { - sessions_[call_->id()].push_back(session); - } - - void PrintStats() const; - void SetupAcceptedCall(); - - typedef std::map RosterMap; - - Console *console_; - buzz::XmppClient* xmpp_client_; - rtc::Thread* worker_thread_; - rtc::NetworkManager* network_manager_; - cricket::PortAllocator* port_allocator_; - cricket::SessionManager* session_manager_; - cricket::SessionManagerTask* session_manager_task_; - cricket::MediaEngineInterface* media_engine_; - cricket::DataEngineInterface* data_engine_; - cricket::MediaSessionClient* media_client_; - MucMap mucs_; - - cricket::Call* call_; - typedef std::map > SessionMap; - SessionMap sessions_; - - buzz::HangoutPubSubClient* hangout_pubsub_client_; - bool incoming_call_; - bool auto_accept_; - std::string pmuc_domain_; - bool render_; - cricket::DataChannelType data_channel_type_; - bool multisession_enabled_; - cricket::VideoRenderer* local_renderer_; - StaticRenderedViews static_rendered_views_; - uint32 static_views_accumulated_count_; - uint32 screencast_ssrc_; - - buzz::PresenceStatus my_status_; - buzz::PresencePushTask* presence_push_; - buzz::PresenceOutTask* presence_out_; - buzz::MucInviteRecvTask* muc_invite_recv_; - buzz::MucInviteSendTask* muc_invite_send_; - buzz::FriendInviteSendTask* friend_invite_send_; - RosterMap* roster_; - uint32 portallocator_flags_; - - bool allow_local_ips_; - cricket::SignalingProtocol signaling_protocol_; - cricket::TransportProtocol transport_protocol_; - cricket::SecurePolicy sdes_policy_; - cricket::SecurePolicy dtls_policy_; - rtc::scoped_ptr ssl_identity_; - std::string last_sent_to_; - - bool show_roster_messages_; -}; - -#endif // WEBRTC_LIBJINGLE_EXAMPLES_CALL_CALLCLIENT_H_ diff --git a/webrtc/libjingle/examples/call/callclient_unittest.cc b/webrtc/libjingle/examples/call/callclient_unittest.cc deleted file mode 100644 index 256853a43..000000000 --- a/webrtc/libjingle/examples/call/callclient_unittest.cc +++ /dev/null @@ -1,47 +0,0 @@ -/* - * libjingle - * Copyright 2008, 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. - */ - -// Unit tests for CallClient - -#include "talk/examples/call/callclient.h" -#include "talk/media/base/filemediaengine.h" -#include "talk/media/base/mediaengine.h" -#include "webrtc/libjingle/xmpp/xmppthread.h" -#include "webrtc/base/gunit.h" - -TEST(CallClientTest, CreateCallClientWithDefaultMediaEngine) { - buzz::XmppPump pump; - CallClient *client = new CallClient(pump.client(), "app", "version"); - delete client; -} - -TEST(CallClientTest, CreateCallClientWithFileMediaEngine) { - buzz::XmppPump pump; - CallClient *client = new CallClient(pump.client(), "app", "version"); - client->SetMediaEngine(new cricket::FileMediaEngine); - delete client; -} diff --git a/webrtc/libjingle/examples/call/console.cc b/webrtc/libjingle/examples/call/console.cc deleted file mode 100644 index 0dfdd4b3a..000000000 --- a/webrtc/libjingle/examples/call/console.cc +++ /dev/null @@ -1,169 +0,0 @@ -/* - * 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. - */ - -#define _CRT_SECURE_NO_DEPRECATE 1 - -#include - -#if defined(WEBRTC_POSIX) -#include -#include -#include -#endif // WEBRTC_POSIX - -#include "talk/examples/call/callclient.h" -#include "talk/examples/call/console.h" -#include "webrtc/base/logging.h" -#include "webrtc/base/messagequeue.h" -#include "webrtc/base/stringutils.h" - -#ifdef WEBRTC_POSIX -static void DoNothing(int unused) {} -#endif - -Console::Console(rtc::Thread *thread, CallClient *client) : - client_(client), - client_thread_(thread), - stopped_(false) {} - -Console::~Console() { - Stop(); -} - -void Console::Start() { - if (stopped_) { - // stdin was closed in Stop(), so we can't restart. - LOG(LS_ERROR) << "Cannot re-start"; - return; - } - if (console_thread_) { - LOG(LS_WARNING) << "Already started"; - return; - } - console_thread_.reset(new rtc::Thread()); - console_thread_->Start(); - console_thread_->Post(this, MSG_START); -} - -void Console::Stop() { - if (console_thread_) { -#ifdef WIN32 - CloseHandle(GetStdHandle(STD_INPUT_HANDLE)); -#else - close(fileno(stdin)); - // This forces the read() in fgets() to return with errno = EINTR. fgets() - // will retry the read() and fail, thus returning. - pthread_kill(console_thread_->GetPThread(), SIGUSR1); -#endif - console_thread_->Stop(); - console_thread_.reset(); - stopped_ = true; - } -} - -void Console::SetEcho(bool on) { -#ifdef WIN32 - HANDLE hIn = GetStdHandle(STD_INPUT_HANDLE); - if ((hIn == INVALID_HANDLE_VALUE) || (hIn == NULL)) - return; - - DWORD mode; - if (!GetConsoleMode(hIn, &mode)) - return; - - if (on) { - mode = mode | ENABLE_ECHO_INPUT; - } else { - mode = mode & ~ENABLE_ECHO_INPUT; - } - - SetConsoleMode(hIn, mode); -#else - const int fd = fileno(stdin); - if (fd == -1) - return; - - struct termios tcflags; - if (tcgetattr(fd, &tcflags) == -1) - return; - - if (on) { - tcflags.c_lflag |= ECHO; - } else { - tcflags.c_lflag &= ~ECHO; - } - - tcsetattr(fd, TCSANOW, &tcflags); -#endif -} - -void Console::PrintLine(const char* format, ...) { - va_list ap; - va_start(ap, format); - - char buf[4096]; - int size = vsnprintf(buf, sizeof(buf), format, ap); - assert(size >= 0); - assert(size < static_cast(sizeof(buf))); - buf[size] = '\0'; - printf("%s\n", buf); - fflush(stdout); - - va_end(ap); -} - -void Console::RunConsole() { - char input_buffer[128]; - while (fgets(input_buffer, sizeof(input_buffer), stdin) != NULL) { - client_thread_->Post(this, MSG_INPUT, - new rtc::TypedMessageData(input_buffer)); - } -} - -void Console::OnMessage(rtc::Message *msg) { - switch (msg->message_id) { - case MSG_START: -#if defined(WEBRTC_POSIX) - // Install a no-op signal so that we can abort RunConsole() by raising - // SIGUSR1. - struct sigaction act; - act.sa_handler = &DoNothing; - sigemptyset(&act.sa_mask); - act.sa_flags = 0; - if (sigaction(SIGUSR1, &act, NULL) < 0) { - LOG(LS_WARNING) << "Can't install signal"; - } -#endif - RunConsole(); - break; - case MSG_INPUT: - rtc::TypedMessageData *data = - static_cast*>(msg->pdata); - client_->ParseLine(data->data()); - break; - } -} diff --git a/webrtc/libjingle/examples/call/console.h b/webrtc/libjingle/examples/call/console.h deleted file mode 100644 index 5f7cb7d12..000000000 --- a/webrtc/libjingle/examples/call/console.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * 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. - */ - -#ifndef WEBRTC_LIBJINGLE_EXAMPLES_CALL_CONSOLE_H_ -#define WEBRTC_LIBJINGLE_EXAMPLES_CALL_CONSOLE_H_ - -#include - -#include "webrtc/base/messagequeue.h" -#include "webrtc/base/scoped_ptr.h" -#include "webrtc/base/thread.h" - -class CallClient; - -class Console : public rtc::MessageHandler { - public: - Console(rtc::Thread *thread, CallClient *client); - ~Console(); - - // Starts reading lines from the console and giving them to the CallClient. - void Start(); - // Stops reading lines. Cannot be restarted. - void Stop(); - - virtual void OnMessage(rtc::Message *msg); - - void PrintLine(const char* format, ...); - - static void SetEcho(bool on); - - private: - enum { - MSG_START, - MSG_INPUT, - }; - - void RunConsole(); - void ParseLine(std::string &str); - - CallClient *client_; - rtc::Thread *client_thread_; - rtc::scoped_ptr console_thread_; - bool stopped_; -}; - -#endif // TALK_EXAMPLES_CALL_CONSOLE_H_ diff --git a/webrtc/libjingle/examples/call/friendinvitesendtask.cc b/webrtc/libjingle/examples/call/friendinvitesendtask.cc deleted file mode 100644 index e2b8ddebd..000000000 --- a/webrtc/libjingle/examples/call/friendinvitesendtask.cc +++ /dev/null @@ -1,76 +0,0 @@ -/* - * 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/examples/call/friendinvitesendtask.h" -#include "webrtc/libjingle/xmpp/constants.h" - -namespace buzz { - -XmppReturnStatus -FriendInviteSendTask::Send(const Jid& user) { - if (GetState() != STATE_INIT && GetState() != STATE_START) - return XMPP_RETURN_BADSTATE; - - // Need to first add to roster, then subscribe to presence. - XmlElement* iq = new XmlElement(QN_IQ); - iq->AddAttr(QN_TYPE, STR_SET); - XmlElement* query = new XmlElement(QN_ROSTER_QUERY); - XmlElement* item = new XmlElement(QN_ROSTER_ITEM); - item->AddAttr(QN_JID, user.Str()); - item->AddAttr(QN_NAME, user.node()); - query->AddElement(item); - iq->AddElement(query); - QueueStanza(iq); - - // Subscribe to presence - XmlElement* presence = new XmlElement(QN_PRESENCE); - presence->AddAttr(QN_TO, user.Str()); - presence->AddAttr(QN_TYPE, STR_SUBSCRIBE); - XmlElement* invitation = new XmlElement(QN_INVITATION); - invitation->AddAttr(QN_INVITE_MESSAGE, - "I've been using Google Talk and thought you might like to try it out. " - "We can use it to call each other for free over the internet. Here's an " - "invitation to download Google Talk. Give it a try!"); - presence->AddElement(invitation); - QueueStanza(presence); - - return XMPP_RETURN_OK; -} - -int -FriendInviteSendTask::ProcessStart() { - const XmlElement* stanza = NextStanza(); - if (stanza == NULL) - return STATE_BLOCKED; - - if (SendStanza(stanza) != XMPP_RETURN_OK) - return STATE_ERROR; - - return STATE_START; -} - -} diff --git a/webrtc/libjingle/examples/call/friendinvitesendtask.h b/webrtc/libjingle/examples/call/friendinvitesendtask.h deleted file mode 100644 index 874e3bba0..000000000 --- a/webrtc/libjingle/examples/call/friendinvitesendtask.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * 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. - */ - -#ifndef WEBRTC_LIBJINGLE_EXAMPLES_CALL_FRIENDINVITESENDTASK_H_ -#define WEBRTC_LIBJINGLE_EXAMPLES_CALL_FRIENDINVITESENDTASK_H_ - -#include "webrtc/libjingle/xmpp/xmppengine.h" -#include "webrtc/libjingle/xmpp/xmpptask.h" - -namespace buzz { - -class FriendInviteSendTask : public XmppTask { -public: - explicit FriendInviteSendTask(XmppTaskParentInterface* parent) - : XmppTask(parent) {} - virtual ~FriendInviteSendTask() {} - - XmppReturnStatus Send(const Jid& user); - - virtual int ProcessStart(); -}; - -} - -#endif diff --git a/webrtc/libjingle/examples/call/mediaenginefactory.cc b/webrtc/libjingle/examples/call/mediaenginefactory.cc deleted file mode 100644 index dd62bf8b0..000000000 --- a/webrtc/libjingle/examples/call/mediaenginefactory.cc +++ /dev/null @@ -1,81 +0,0 @@ -// -// libjingle -// Copyright 2004--2007, 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/examples/call/mediaenginefactory.h" - -#include "talk/media/base/fakemediaengine.h" -#include "talk/media/base/filemediaengine.h" -#include "talk/media/base/mediaengine.h" -#include "webrtc/base/stringutils.h" - -std::vector RequiredAudioCodecs() { - std::vector audio_codecs; - audio_codecs.push_back( - cricket::AudioCodec(9, "G722", 16000, 0, 1, 0)); - audio_codecs.push_back( - cricket::AudioCodec(0, "PCMU", 8000, 0, 1, 0)); - audio_codecs.push_back( - cricket::AudioCodec(13, "CN", 8000, 0, 1, 0)); - audio_codecs.push_back( - cricket::AudioCodec(105, "CN", 16000, 0, 1, 0)); - return audio_codecs; -} - -std::vector RequiredVideoCodecs() { - std::vector video_codecs; - video_codecs.push_back( - cricket::VideoCodec(97, "H264", 320, 240, 30, 0)); - video_codecs.push_back( - cricket::VideoCodec(99, "H264-SVC", 640, 360, 30, 0)); - return video_codecs; -} - -cricket::MediaEngineInterface* MediaEngineFactory::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) { - file_media_engine->set_voice_input_filename(voice_in); - } - if (voice_out) { - file_media_engine->set_voice_output_filename(voice_out); - } - if (video_in) { - file_media_engine->set_video_input_filename(video_in); - } - if (video_out) { - file_media_engine->set_video_output_filename(video_out); - } - - // Set voice and video codecs. TODO: The codecs actually depend on - // the the input voice and video streams. - file_media_engine->set_voice_codecs(RequiredAudioCodecs()); - file_media_engine->set_video_codecs(RequiredVideoCodecs()); - - return file_media_engine; -} diff --git a/webrtc/libjingle/examples/call/mediaenginefactory.h b/webrtc/libjingle/examples/call/mediaenginefactory.h deleted file mode 100644 index c120bdf98..000000000 --- a/webrtc/libjingle/examples/call/mediaenginefactory.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * libjingle - * Copyright 2011, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef WEBRTC_LIBJINGLE_EXAMPLES_CALL_MEDIAENGINEFACTORY_H_ -#define WEBRTC_LIBJINGLE_EXAMPLES_CALL_MEDIAENGINEFACTORY_H_ - -#include "talk/media/base/mediaengine.h" - -class MediaEngineFactory { - public: - static cricket::MediaEngineInterface* CreateFileMediaEngine( - const char* voice_in, const char* voice_out, - const char* video_in, const char* video_out); -}; - -#endif // WEBRTC_LIBJINGLE_EXAMPLES_CALL_MEDIAENGINEFACTORY_H_ diff --git a/webrtc/libjingle/examples/call/muc.h b/webrtc/libjingle/examples/call/muc.h deleted file mode 100644 index 07a745628..000000000 --- a/webrtc/libjingle/examples/call/muc.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * 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. - */ - -#ifndef WEBRTC_LIBJINGLE_EXAMPLES_CALL_MUC_H_ -#define WEBRTC_LIBJINGLE_EXAMPLES_CALL_MUC_H_ - -#include -#include "webrtc/libjingle/xmpp/jid.h" -#include "webrtc/libjingle/xmpp/presencestatus.h" - -namespace buzz { - -class Muc { - public: - Muc(const Jid& jid, const std::string& nick) : state_(MUC_JOINING), - jid_(jid), local_jid_(Jid(jid.Str() + "/" + nick)) {} - ~Muc() {}; - - enum State { MUC_JOINING, MUC_JOINED, MUC_LEAVING }; - State state() const { return state_; } - void set_state(State state) { state_ = state; } - const Jid & jid() const { return jid_; } - const Jid & local_jid() const { return local_jid_; } - - typedef std::map MemberMap; - - // All the intelligence about how to manage the members is in - // CallClient, so we completely expose the map. - MemberMap& members() { - return members_; - } - -private: - State state_; - Jid jid_; - Jid local_jid_; - MemberMap members_; -}; - -} - -#endif diff --git a/webrtc/libjingle/examples/call/mucinviterecvtask.cc b/webrtc/libjingle/examples/call/mucinviterecvtask.cc deleted file mode 100644 index 32de8fe8d..000000000 --- a/webrtc/libjingle/examples/call/mucinviterecvtask.cc +++ /dev/null @@ -1,124 +0,0 @@ -/* - * 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/examples/call/mucinviterecvtask.h" -#include "webrtc/libjingle/xmpp/constants.h" - -namespace buzz { - -const char* types[] = { - "unknown", - "audio", - "video", -}; - -const char* statuses[] = { - "unknown", - "sendrecv", - "sendonly", - "recvonly", - "inactive", -}; - -const char* -AvailableMediaEntry::TypeAsString(type_t type) { - // The values of the constants have been chosen such that this is correct. - return types[type]; -} - -const char* -AvailableMediaEntry::StatusAsString(status_t status) { - // The values of the constants have been chosen such that this is correct. - return statuses[status]; -} - -int bodytext_to_array_pos(const XmlElement* elem, const char* array[], - int len, int defval = -1) { - if (elem) { - const std::string& body(elem->BodyText()); - for (int i = 0; i < len; ++i) { - if (body == array[i]) { - // Found it. - return i; - } - } - } - // If we get here, it's not any value in the array. - return defval; -} - -bool -MucInviteRecvTask::HandleStanza(const XmlElement* stanza) { - // Figuring out that we want to handle this is a lot of the work of - // actually handling it, so we handle it right here instead of queueing it. - const XmlElement* xstanza; - const XmlElement* invite; - if (stanza->Name() != QN_MESSAGE) return false; - xstanza = stanza->FirstNamed(QN_MUC_USER_X); - if (!xstanza) return false; - invite = xstanza->FirstNamed(QN_MUC_USER_INVITE); - if (!invite) return false; - // Else it's an invite and we definitely want to handle it. Parse the - // available-media, if any. - std::vector v; - const XmlElement* avail = - invite->FirstNamed(QN_GOOGLE_MUC_USER_AVAILABLE_MEDIA); - if (avail) { - for (const XmlElement* entry = avail->FirstNamed(QN_GOOGLE_MUC_USER_ENTRY); - entry; - entry = entry->NextNamed(QN_GOOGLE_MUC_USER_ENTRY)) { - AvailableMediaEntry tmp; - // In the interest of debugging, we accept as much valid-looking data - // as we can. - tmp.label = atoi(entry->Attr(QN_LABEL).c_str()); - tmp.type = static_cast( - bodytext_to_array_pos( - entry->FirstNamed(QN_GOOGLE_MUC_USER_TYPE), - types, - sizeof(types)/sizeof(const char*), - AvailableMediaEntry::TYPE_UNKNOWN)); - tmp.status = static_cast( - bodytext_to_array_pos( - entry->FirstNamed(QN_GOOGLE_MUC_USER_STATUS), - statuses, - sizeof(statuses)/sizeof(const char*), - AvailableMediaEntry::STATUS_UNKNOWN)); - v.push_back(tmp); - } - } - SignalInviteReceived(Jid(invite->Attr(QN_FROM)), Jid(stanza->Attr(QN_FROM)), - v); - return true; -} - -int -MucInviteRecvTask::ProcessStart() { - // We never queue anything so we are always blocked. - return STATE_BLOCKED; -} - -} diff --git a/webrtc/libjingle/examples/call/mucinviterecvtask.h b/webrtc/libjingle/examples/call/mucinviterecvtask.h deleted file mode 100644 index 293f67bf7..000000000 --- a/webrtc/libjingle/examples/call/mucinviterecvtask.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * 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. - */ - -#ifndef WEBRTC_LIBJINGLE_EXAMPLES_CALL_MUCINVITERECVTASK_H_ -#define WEBRTC_LIBJINGLE_EXAMPLES_CALL_MUCINVITERECVTASK_H_ - -#include - -#include "webrtc/libjingle/xmpp/xmppengine.h" -#include "webrtc/libjingle/xmpp/xmpptask.h" -#include "webrtc/base/sigslot.h" - -namespace buzz { - -struct AvailableMediaEntry { - enum type_t { - // SIP defines other media types, but these are the only ones we use in - // multiway jingle. - // These numbers are important; see .cc file - TYPE_UNKNOWN = 0, // indicates invalid string - TYPE_AUDIO = 1, - TYPE_VIDEO = 2, - }; - - enum status_t { - // These numbers are important; see .cc file - STATUS_UNKNOWN = 0, // indicates invalid string - STATUS_SENDRECV = 1, - STATUS_SENDONLY = 2, - STATUS_RECVONLY = 3, - STATUS_INACTIVE = 4, - }; - - uint32 label; - type_t type; - status_t status; - - static const char* TypeAsString(type_t type); - static const char* StatusAsString(status_t status); -}; - -class MucInviteRecvTask : public XmppTask { - public: - 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& > SignalInviteReceived; - - protected: - virtual bool HandleStanza(const XmlElement* stanza); - -}; - -} - -#endif diff --git a/webrtc/libjingle/examples/call/mucinvitesendtask.cc b/webrtc/libjingle/examples/call/mucinvitesendtask.cc deleted file mode 100644 index 2299b78aa..000000000 --- a/webrtc/libjingle/examples/call/mucinvitesendtask.cc +++ /dev/null @@ -1,63 +0,0 @@ -/* - * 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/examples/call/mucinvitesendtask.h" -#include "webrtc/libjingle/xmpp/constants.h" -#include "webrtc/libjingle/xmpp/xmppclient.h" - -namespace buzz { - -XmppReturnStatus -MucInviteSendTask::Send(const Jid& to, const Jid& invitee) { - if (GetState() != STATE_INIT && GetState() != STATE_START) - return XMPP_RETURN_BADSTATE; - - XmlElement* message = new XmlElement(QN_MESSAGE); - message->AddAttr(QN_TO, to.Str()); - XmlElement* xstanza = new XmlElement(QN_MUC_USER_X); - XmlElement* invite = new XmlElement(QN_MUC_USER_INVITE); - invite->AddAttr(QN_TO, invitee.Str()); - xstanza->AddElement(invite); - message->AddElement(xstanza); - - QueueStanza(message); - return XMPP_RETURN_OK; -} - -int -MucInviteSendTask::ProcessStart() { - const XmlElement* stanza = NextStanza(); - if (stanza == NULL) - return STATE_BLOCKED; - - if (SendStanza(stanza) != XMPP_RETURN_OK) - return STATE_ERROR; - - return STATE_START; -} - -} diff --git a/webrtc/libjingle/examples/call/mucinvitesendtask.h b/webrtc/libjingle/examples/call/mucinvitesendtask.h deleted file mode 100644 index fecb59b71..000000000 --- a/webrtc/libjingle/examples/call/mucinvitesendtask.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * 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. - */ - -#ifndef WEBRTC_LIBJINGLE_EXAMPLES_CALL_MUCINVITESENDTASK_H_ -#define WEBRTC_LIBJINGLE_EXAMPLES_CALL_MUCINVITESENDTASK_H_ - -#include "talk/examples/call/muc.h" -#include "webrtc/libjingle/xmpp/xmppengine.h" -#include "webrtc/libjingle/xmpp/xmpptask.h" - -namespace buzz { - -class MucInviteSendTask : public XmppTask { -public: - explicit MucInviteSendTask(XmppTaskParentInterface* parent) - : XmppTask(parent) {} - virtual ~MucInviteSendTask() {} - - XmppReturnStatus Send(const Jid& to, const Jid& invitee); - - virtual int ProcessStart(); -}; - -} - -#endif diff --git a/webrtc/libjingle/examples/call/presencepushtask.cc b/webrtc/libjingle/examples/call/presencepushtask.cc deleted file mode 100644 index 8d8dca80e..000000000 --- a/webrtc/libjingle/examples/call/presencepushtask.cc +++ /dev/null @@ -1,222 +0,0 @@ -/* - * 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/examples/call/presencepushtask.h" - -#include "talk/examples/call/muc.h" -#include "webrtc/libjingle/xmpp/constants.h" -#include "webrtc/base/stringencode.h" - - - -namespace buzz { - -// string helper functions ----------------------------------------------------- - -static bool -IsXmlSpace(int ch) { - return ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t'; -} - -static bool ListContainsToken(const std::string & list, - const std::string & token) { - size_t i = list.find(token); - if (i == std::string::npos || token.empty()) - return false; - bool boundary_before = (i == 0 || IsXmlSpace(list[i - 1])); - bool boundary_after = (i == list.length() - token.length() || - IsXmlSpace(list[i + token.length()])); - return boundary_before && boundary_after; -} - - -bool PresencePushTask::HandleStanza(const XmlElement * stanza) { - if (stanza->Name() != QN_PRESENCE) - return false; - QueueStanza(stanza); - return true; -} - -static bool IsUtf8FirstByte(int c) { - return (((c)&0x80)==0) || // is single byte - ((unsigned char)((c)-0xc0)<0x3e); // or is lead byte -} - -int PresencePushTask::ProcessStart() { - const XmlElement * stanza = NextStanza(); - if (stanza == NULL) - return STATE_BLOCKED; - - Jid from(stanza->Attr(QN_FROM)); - std::map::const_iterator elem = - client_->mucs().find(from.BareJid()); - if (elem == client_->mucs().end()) { - HandlePresence(from, stanza); - } else { - HandleMucPresence(elem->second, from, stanza); - } - - return STATE_START; -} - -void PresencePushTask::HandlePresence(const Jid& from, - const XmlElement* stanza) { - if (stanza->Attr(QN_TYPE) == STR_ERROR) - return; - - PresenceStatus s; - FillStatus(from, stanza, &s); - SignalStatusUpdate(s); -} - -void PresencePushTask::HandleMucPresence(buzz::Muc* muc, - const Jid& from, - const XmlElement* stanza) { - if (from == muc->local_jid()) { - if (!stanza->HasAttr(QN_TYPE)) { - // We joined the MUC. - const XmlElement* elem = stanza->FirstNamed(QN_MUC_USER_X); - // Status code=110 or 100 is not guaranteed to be present, so we - // only check the item element and Muc join status. - if (elem) { - if (elem->FirstNamed(QN_MUC_USER_ITEM) && - muc->state() == buzz::Muc::MUC_JOINING) { - SignalMucJoined(muc->jid()); - } - } - } else { - // We've been kicked. Bye. - int error = 0; - if (stanza->Attr(QN_TYPE) == STR_ERROR) { - const XmlElement* elem = stanza->FirstNamed(QN_ERROR); - if (elem && elem->HasAttr(QN_CODE)) { - error = atoi(elem->Attr(QN_CODE).c_str()); - } - } - SignalMucLeft(muc->jid(), error); - } - } else { - MucPresenceStatus s; - FillMucStatus(from, stanza, &s); - SignalMucStatusUpdate(muc->jid(), s); - } -} - -void PresencePushTask::FillStatus(const Jid& from, const XmlElement* stanza, - PresenceStatus* s) { - s->set_jid(from); - if (stanza->Attr(QN_TYPE) == STR_UNAVAILABLE) { - s->set_available(false); - } else { - s->set_available(true); - const XmlElement * status = stanza->FirstNamed(QN_STATUS); - if (status != NULL) { - s->set_status(status->BodyText()); - - // Truncate status messages longer than 300 bytes - if (s->status().length() > 300) { - size_t len = 300; - - // Be careful not to split legal utf-8 chars in half - while (!IsUtf8FirstByte(s->status()[len]) && len > 0) { - len -= 1; - } - std::string truncated(s->status(), 0, len); - s->set_status(truncated); - } - } - - const XmlElement * priority = stanza->FirstNamed(QN_PRIORITY); - if (priority != NULL) { - int pri; - if (rtc::FromString(priority->BodyText(), &pri)) { - s->set_priority(pri); - } - } - - const XmlElement * show = stanza->FirstNamed(QN_SHOW); - if (show == NULL || show->FirstChild() == NULL) { - s->set_show(PresenceStatus::SHOW_ONLINE); - } - else { - if (show->BodyText() == "away") { - s->set_show(PresenceStatus::SHOW_AWAY); - } - else if (show->BodyText() == "xa") { - s->set_show(PresenceStatus::SHOW_XA); - } - else if (show->BodyText() == "dnd") { - s->set_show(PresenceStatus::SHOW_DND); - } - else if (show->BodyText() == "chat") { - s->set_show(PresenceStatus::SHOW_CHAT); - } - else { - s->set_show(PresenceStatus::SHOW_ONLINE); - } - } - - const XmlElement * caps = stanza->FirstNamed(QN_CAPS_C); - if (caps != NULL) { - std::string node = caps->Attr(QN_NODE); - std::string ver = caps->Attr(QN_VER); - std::string exts = caps->Attr(QN_EXT); - - s->set_know_capabilities(true); - s->set_caps_node(node); - s->set_version(ver); - - if (ListContainsToken(exts, "voice-v1")) { - s->set_voice_capability(true); - } - if (ListContainsToken(exts, "video-v1")) { - s->set_video_capability(true); - } - } - - const XmlElement* delay = stanza->FirstNamed(kQnDelayX); - if (delay != NULL) { - // Ideally we would parse this according to the Psuedo ISO-8601 rules - // that are laid out in JEP-0082: - // http://www.jabber.org/jeps/jep-0082.html - std::string stamp = delay->Attr(kQnStamp); - s->set_sent_time(stamp); - } - - const XmlElement* nick = stanza->FirstNamed(QN_NICKNAME); - if (nick) { - s->set_nick(nick->BodyText()); - } - } -} - -void PresencePushTask::FillMucStatus(const Jid& from, const XmlElement* stanza, - MucPresenceStatus* s) { - FillStatus(from, stanza, s); -} - -} diff --git a/webrtc/libjingle/examples/call/presencepushtask.h b/webrtc/libjingle/examples/call/presencepushtask.h deleted file mode 100644 index c93ae5650..000000000 --- a/webrtc/libjingle/examples/call/presencepushtask.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * 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. - */ - -#ifndef WEBRTC_LIBJINGLE_EXAMPLES_CALL_PRESENCEPUSHTASK_H_ -#define WEBRTC_LIBJINGLE_EXAMPLES_CALL_PRESENCEPUSHTASK_H_ - -#include - -#include "talk/examples/call/callclient.h" -#include "webrtc/libjingle/xmpp/presencestatus.h" -#include "webrtc/libjingle/xmpp/xmppengine.h" -#include "webrtc/libjingle/xmpp/xmpptask.h" -#include "webrtc/base/sigslot.h" - -namespace buzz { - -class PresencePushTask : public XmppTask { - public: - PresencePushTask(XmppTaskParentInterface* parent, CallClient* client) - : XmppTask(parent, XmppEngine::HL_TYPE), - client_(client) {} - virtual int ProcessStart(); - - sigslot::signal1 SignalStatusUpdate; - sigslot::signal1 SignalMucJoined; - sigslot::signal2 SignalMucLeft; - sigslot::signal2 SignalMucStatusUpdate; - - protected: - virtual bool HandleStanza(const XmlElement * stanza); - void HandlePresence(const Jid& from, const XmlElement * stanza); - void HandleMucPresence(buzz::Muc* muc, - const Jid& from, const XmlElement * stanza); - static void FillStatus(const Jid& from, const XmlElement * stanza, - PresenceStatus* status); - static void FillMucStatus(const Jid& from, const XmlElement * stanza, - MucPresenceStatus* status); - - private: - CallClient* client_; -}; - - -} - -#endif diff --git a/webrtc/libjingle/examples/login/login_main.cc b/webrtc/libjingle/examples/login/login_main.cc deleted file mode 100644 index 581c98690..000000000 --- a/webrtc/libjingle/examples/login/login_main.cc +++ /dev/null @@ -1,67 +0,0 @@ -/* - * 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 - -#include - -#include "webrtc/libjingle/xmpp/constants.h" -#include "webrtc/libjingle/xmpp/xmppclientsettings.h" -#include "webrtc/libjingle/xmpp/xmppengine.h" -#include "webrtc/libjingle/xmpp/xmppthread.h" -#include "webrtc/base/thread.h" - -int main(int argc, char **argv) { - std::cout << "OAuth Access Token: "; - std::string auth_token; - std::getline(std::cin, auth_token); - - std::cout << "User Name: "; - std::string username; - std::getline(std::cin, username); - - // Start xmpp on a different thread - buzz::XmppThread thread; - thread.Start(); - - buzz::XmppClientSettings xcs; - xcs.set_user(username.c_str()); - xcs.set_host("gmail.com"); - xcs.set_use_tls(buzz::TLS_DISABLED); - xcs.set_auth_token(buzz::AUTH_MECHANISM_OAUTH2, - auth_token.c_str()); - xcs.set_server(rtc::SocketAddress("talk.google.com", 5222)); - thread.Login(xcs); - - // Use main thread for console input - std::string line; - while (std::getline(std::cin, line)) { - if (line == "quit") - break; - } - return 0; -} diff --git a/webrtc/libjingle/libjingle.gyp b/webrtc/libjingle/libjingle.gyp index f92f346f9..3c3996905 100644 --- a/webrtc/libjingle/libjingle.gyp +++ b/webrtc/libjingle/libjingle.gyp @@ -31,164 +31,5 @@ 'xmpp/jingleinfotask.h', ], }, # target libjingle_xmpphelp - { - 'target_name': 'jingle_session', - 'type': 'static_library', - 'dependencies': [ - '<(talk_root)/libjingle.gyp:libjingle_media', - '<(webrtc_root)/base/base.gyp:rtc_base', - '<(webrtc_root)/common.gyp:webrtc_common', - '<(webrtc_root)/libjingle/xmpp/xmpp.gyp:rtc_xmpp', - ], - 'cflags_cc!': [ - '-Wnon-virtual-dtor', - ], - 'sources': [ - 'session/constants.cc', - 'session/constants.h', - 'session/p2ptransportparser.cc', - 'session/p2ptransportparser.h', - 'session/parsing.cc', - 'session/parsing.h', - 'session/rawtransportparser.cc', - 'session/rawtransportparser.h', - 'session/sessionclient.h', - 'session/sessionmanager.h', - 'session/sessionmanager.cc', - 'session/sessionmanagertask.h', - 'session/sessionmessages.cc', - 'session/sessionmessages.h', - 'session/sessionsendtask.h', - 'session/transportparser.cc', - 'session/transportparser.h', - 'session/media/call.cc', - 'session/media/call.h', - 'session/media/mediasessionclient.cc', - 'session/media/mediasessionclient.h', - 'session/media/mediamessages.cc', - 'session/media/mediamessages.h', - 'session/tunnel/pseudotcpchannel.cc', - 'session/tunnel/pseudotcpchannel.h', - 'session/tunnel/tunnelsessionclient.cc', - 'session/tunnel/tunnelsessionclient.h', - 'session/tunnel/securetunnelsessionclient.cc', - 'session/tunnel/securetunnelsessionclient.h', - ], - 'direct_dependent_settings': { - 'cflags_cc!': [ - '-Wnon-virtual-dtor', - ], - 'defines': [ - 'FEATURE_ENABLE_VOICEMAIL', - ], - }, - 'conditions': [ - ['build_with_chromium==0', { - 'defines': [ - 'FEATURE_ENABLE_VOICEMAIL', - 'FEATURE_ENABLE_PSTN', - ], - }], - ['build_expat==1', { - 'dependencies': [ - '<(DEPTH)/third_party/expat/expat.gyp:expat', - ], - 'export_dependent_settings': [ - '<(DEPTH)/third_party/expat/expat.gyp:expat', - ], - }], - ], - }, - { - 'target_name': 'jingle_session_unittest', - 'type': 'executable', - 'dependencies': [ - 'jingle_session', - '<(webrtc_root)/base/base_tests.gyp:rtc_base_tests_utils', - '<(talk_root)/libjingle.gyp:libjingle', - '<(talk_root)/libjingle.gyp:libjingle_p2p', - '<(talk_root)/libjingle_tests.gyp:libjingle_unittest_main', - ], - 'sources': [ - 'session/media/mediamessages_unittest.cc', - 'session/media/mediasessionclient_unittest.cc', - 'session/session_unittest.cc', - 'session/transportparser_unittest.cc', - ], - 'conditions': [ - ['OS=="win"', { - 'msvs_settings': { - 'VCLinkerTool': { - 'AdditionalDependencies': [ - 'strmiids.lib', - ], - }, - }, - }], - ], - }, # target jingle_session_unittest - { - 'target_name': 'login', - 'type': 'executable', - 'dependencies': [ - 'libjingle_xmpphelp', - '<(talk_root)/libjingle.gyp:libjingle', - ], - 'sources': [ - 'examples/login/login_main.cc', - ], - }, # target login - ], - 'conditions': [ - # TODO(ronghuawu): Reenable building call. - # ['OS!="android"', { - # 'targets': [ - # { - # 'target_name': 'call', - # 'type': 'executable', - # 'dependencies': [ - # 'libjingle.gyp:libjingle_p2p', - # 'libjingle_xmpphelp', - # ], - # 'sources': [ - # 'examples/call/call_main.cc', - # 'examples/call/callclient.cc', - # 'examples/call/callclient.h', - # 'examples/call/console.cc', - # 'examples/call/console.h', - # 'examples/call/friendinvitesendtask.cc', - # 'examples/call/friendinvitesendtask.h', - # 'examples/call/mediaenginefactory.cc', - # 'examples/call/mediaenginefactory.h', - # 'examples/call/muc.h', - # 'examples/call/mucinviterecvtask.cc', - # 'examples/call/mucinviterecvtask.h', - # 'examples/call/mucinvitesendtask.cc', - # 'examples/call/mucinvitesendtask.h', - # 'examples/call/presencepushtask.cc', - # 'examples/call/presencepushtask.h', - # ], - # 'conditions': [ - # ['OS=="linux"', { - # 'link_settings': { - # 'libraries': [ - # ' - -#include "webrtc/libjingle/xmllite/qname.h" -#include "webrtc/p2p/base/constants.h" - -namespace cricket { - -const char NS_EMPTY[] = ""; -const char NS_JINGLE[] = "urn:xmpp:jingle:1"; -const char NS_JINGLE_DRAFT[] = "google:jingle"; -const char NS_GINGLE[] = "http://www.google.com/session"; - -// actions (aka or ) -const buzz::StaticQName QN_ACTION = { NS_EMPTY, "action" }; -const char LN_INITIATOR[] = "initiator"; -const buzz::StaticQName QN_INITIATOR = { NS_EMPTY, LN_INITIATOR }; -const buzz::StaticQName QN_CREATOR = { NS_EMPTY, "creator" }; - -const buzz::StaticQName QN_JINGLE = { NS_JINGLE, "jingle" }; -const buzz::StaticQName QN_JINGLE_CONTENT = { NS_JINGLE, "content" }; -const buzz::StaticQName QN_JINGLE_CONTENT_NAME = { NS_EMPTY, "name" }; -const buzz::StaticQName QN_JINGLE_CONTENT_MEDIA = { NS_EMPTY, "media" }; -const buzz::StaticQName QN_JINGLE_REASON = { NS_JINGLE, "reason" }; -const buzz::StaticQName QN_JINGLE_DRAFT_GROUP = { NS_JINGLE_DRAFT, "group" }; -const buzz::StaticQName QN_JINGLE_DRAFT_GROUP_TYPE = { NS_EMPTY, "type" }; -const char JINGLE_CONTENT_MEDIA_AUDIO[] = "audio"; -const char JINGLE_CONTENT_MEDIA_VIDEO[] = "video"; -const char JINGLE_CONTENT_MEDIA_DATA[] = "data"; -const char JINGLE_ACTION_SESSION_INITIATE[] = "session-initiate"; -const char JINGLE_ACTION_SESSION_INFO[] = "session-info"; -const char JINGLE_ACTION_SESSION_ACCEPT[] = "session-accept"; -const char JINGLE_ACTION_SESSION_TERMINATE[] = "session-terminate"; -const char JINGLE_ACTION_TRANSPORT_INFO[] = "transport-info"; -const char JINGLE_ACTION_TRANSPORT_ACCEPT[] = "transport-accept"; -const char JINGLE_ACTION_DESCRIPTION_INFO[] = "description-info"; - -const buzz::StaticQName QN_GINGLE_SESSION = { NS_GINGLE, "session" }; -const char GINGLE_ACTION_INITIATE[] = "initiate"; -const char GINGLE_ACTION_INFO[] = "info"; -const char GINGLE_ACTION_ACCEPT[] = "accept"; -const char GINGLE_ACTION_REJECT[] = "reject"; -const char GINGLE_ACTION_TERMINATE[] = "terminate"; -const char GINGLE_ACTION_CANDIDATES[] = "candidates"; -const char GINGLE_ACTION_UPDATE[] = "update"; - -const char LN_ERROR[] = "error"; -const buzz::StaticQName QN_GINGLE_REDIRECT = { NS_GINGLE, "redirect" }; -const char STR_REDIRECT_PREFIX[] = "xmpp:"; - -// Session Contents (aka Gingle -// or Jingle ) -const char LN_DESCRIPTION[] = "description"; -const char LN_PAYLOADTYPE[] = "payload-type"; -const buzz::StaticQName QN_ID = { NS_EMPTY, "id" }; -const buzz::StaticQName QN_SID = { NS_EMPTY, "sid" }; -const buzz::StaticQName QN_NAME = { NS_EMPTY, "name" }; -const buzz::StaticQName QN_CLOCKRATE = { NS_EMPTY, "clockrate" }; -const buzz::StaticQName QN_BITRATE = { NS_EMPTY, "bitrate" }; -const buzz::StaticQName QN_CHANNELS = { NS_EMPTY, "channels" }; -const buzz::StaticQName QN_WIDTH = { NS_EMPTY, "width" }; -const buzz::StaticQName QN_HEIGHT = { NS_EMPTY, "height" }; -const buzz::StaticQName QN_FRAMERATE = { NS_EMPTY, "framerate" }; -const char LN_NAME[] = "name"; -const char LN_VALUE[] = "value"; -const buzz::StaticQName QN_PAYLOADTYPE_PARAMETER_NAME = { NS_EMPTY, LN_NAME }; -const buzz::StaticQName QN_PAYLOADTYPE_PARAMETER_VALUE = { NS_EMPTY, LN_VALUE }; -const char PAYLOADTYPE_PARAMETER_BITRATE[] = "bitrate"; -const char PAYLOADTYPE_PARAMETER_HEIGHT[] = "height"; -const char PAYLOADTYPE_PARAMETER_WIDTH[] = "width"; -const char PAYLOADTYPE_PARAMETER_FRAMERATE[] = "framerate"; -const char LN_BANDWIDTH[] = "bandwidth"; - -const buzz::StaticQName QN_JINGLE_RTP_CONTENT = - { NS_JINGLE_RTP, LN_DESCRIPTION }; -const buzz::StaticQName QN_SSRC = { NS_EMPTY, "ssrc" }; -const buzz::StaticQName QN_JINGLE_RTP_PAYLOADTYPE = - { NS_JINGLE_RTP, LN_PAYLOADTYPE }; -const buzz::StaticQName QN_JINGLE_RTP_BANDWIDTH = - { NS_JINGLE_RTP, LN_BANDWIDTH }; -const buzz::StaticQName QN_JINGLE_RTCP_MUX = { NS_JINGLE_RTP, "rtcp-mux" }; -const buzz::StaticQName QN_JINGLE_RTCP_FB = { NS_JINGLE_RTP, "rtcp-fb" }; -const buzz::StaticQName QN_SUBTYPE = { NS_EMPTY, "subtype" }; -const buzz::StaticQName QN_PARAMETER = { NS_JINGLE_RTP, "parameter" }; -const buzz::StaticQName QN_JINGLE_RTP_HDREXT = - { NS_JINGLE_RTP, "rtp-hdrext" }; -const buzz::StaticQName QN_URI = { NS_EMPTY, "uri" }; - -const buzz::StaticQName QN_JINGLE_DRAFT_SCTP_CONTENT = - { NS_JINGLE_DRAFT_SCTP, LN_DESCRIPTION }; -const buzz::StaticQName QN_JINGLE_DRAFT_SCTP_STREAM = - { NS_JINGLE_DRAFT_SCTP, "stream" }; - -const char NS_GINGLE_AUDIO[] = "http://www.google.com/session/phone"; -const buzz::StaticQName QN_GINGLE_AUDIO_CONTENT = - { NS_GINGLE_AUDIO, LN_DESCRIPTION }; -const buzz::StaticQName QN_GINGLE_AUDIO_PAYLOADTYPE = - { NS_GINGLE_AUDIO, LN_PAYLOADTYPE }; -const buzz::StaticQName QN_GINGLE_AUDIO_SRCID = { NS_GINGLE_AUDIO, "src-id" }; -const char NS_GINGLE_VIDEO[] = "http://www.google.com/session/video"; -const buzz::StaticQName QN_GINGLE_VIDEO_CONTENT = - { NS_GINGLE_VIDEO, LN_DESCRIPTION }; -const buzz::StaticQName QN_GINGLE_VIDEO_PAYLOADTYPE = - { NS_GINGLE_VIDEO, LN_PAYLOADTYPE }; -const buzz::StaticQName QN_GINGLE_VIDEO_SRCID = { NS_GINGLE_VIDEO, "src-id" }; -const buzz::StaticQName QN_GINGLE_VIDEO_BANDWIDTH = - { NS_GINGLE_VIDEO, LN_BANDWIDTH }; - -// Crypto support. -const buzz::StaticQName QN_ENCRYPTION = { NS_JINGLE_RTP, "encryption" }; -const buzz::StaticQName QN_ENCRYPTION_REQUIRED = { NS_EMPTY, "required" }; -const buzz::StaticQName QN_CRYPTO = { NS_JINGLE_RTP, "crypto" }; -const buzz::StaticQName QN_GINGLE_AUDIO_CRYPTO_USAGE = - { NS_GINGLE_AUDIO, "usage" }; -const buzz::StaticQName QN_GINGLE_VIDEO_CRYPTO_USAGE = - { NS_GINGLE_VIDEO, "usage" }; -const buzz::StaticQName QN_CRYPTO_SUITE = { NS_EMPTY, "crypto-suite" }; -const buzz::StaticQName QN_CRYPTO_KEY_PARAMS = { NS_EMPTY, "key-params" }; -const buzz::StaticQName QN_CRYPTO_TAG = { NS_EMPTY, "tag" }; -const buzz::StaticQName QN_CRYPTO_SESSION_PARAMS = - { NS_EMPTY, "session-params" }; - -// Transports and candidates. -const char LN_TRANSPORT[] = "transport"; -const char LN_CANDIDATE[] = "candidate"; -const buzz::StaticQName QN_UFRAG = { cricket::NS_EMPTY, "ufrag" }; -const buzz::StaticQName QN_PWD = { cricket::NS_EMPTY, "pwd" }; -const buzz::StaticQName QN_COMPONENT = { cricket::NS_EMPTY, "component" }; -const buzz::StaticQName QN_IP = { cricket::NS_EMPTY, "ip" }; -const buzz::StaticQName QN_PORT = { cricket::NS_EMPTY, "port" }; -const buzz::StaticQName QN_NETWORK = { cricket::NS_EMPTY, "network" }; -const buzz::StaticQName QN_GENERATION = { cricket::NS_EMPTY, "generation" }; -const buzz::StaticQName QN_PRIORITY = { cricket::NS_EMPTY, "priority" }; -const buzz::StaticQName QN_PROTOCOL = { cricket::NS_EMPTY, "protocol" }; -const char ICE_CANDIDATE_TYPE_PEER_STUN[] = "prflx"; -const char ICE_CANDIDATE_TYPE_SERVER_STUN[] = "srflx"; - -const buzz::StaticQName QN_FINGERPRINT = { cricket::NS_EMPTY, "fingerprint" }; -const buzz::StaticQName QN_FINGERPRINT_ALGORITHM = - { cricket::NS_EMPTY, "algorithm" }; -const buzz::StaticQName QN_FINGERPRINT_DIGEST = { cricket::NS_EMPTY, "digest" }; - -const buzz::StaticQName QN_GINGLE_P2P_TRANSPORT = - { NS_GINGLE_P2P, LN_TRANSPORT }; -const buzz::StaticQName QN_GINGLE_P2P_CANDIDATE = - { NS_GINGLE_P2P, LN_CANDIDATE }; -const buzz::StaticQName QN_GINGLE_P2P_UNKNOWN_CHANNEL_NAME = - { NS_GINGLE_P2P, "unknown-channel-name" }; -const buzz::StaticQName QN_GINGLE_CANDIDATE = { NS_GINGLE, LN_CANDIDATE }; -const buzz::StaticQName QN_ADDRESS = { cricket::NS_EMPTY, "address" }; -const buzz::StaticQName QN_USERNAME = { cricket::NS_EMPTY, "username" }; -const buzz::StaticQName QN_PASSWORD = { cricket::NS_EMPTY, "password" }; -const buzz::StaticQName QN_PREFERENCE = { cricket::NS_EMPTY, "preference" }; - -// terminate reasons and errors -const char JINGLE_ERROR_BAD_REQUEST[] = "bad-request"; -const char JINGLE_ERROR_OUT_OF_ORDER[] = "out-of-order"; -const char JINGLE_ERROR_UNKNOWN_SESSION[] = "unknown-session"; - -// Call terminate reasons from XEP-166 -const char STR_TERMINATE_DECLINE[] = "decline"; -const char STR_TERMINATE_SUCCESS[] = "success"; -const char STR_TERMINATE_ERROR[] = "general-error"; -const char STR_TERMINATE_INCOMPATIBLE_PARAMETERS[] = "incompatible-parameters"; - -// Old terminate reasons used by cricket -const char STR_TERMINATE_CALL_ENDED[] = "call-ended"; -const char STR_TERMINATE_RECIPIENT_UNAVAILABLE[] = "recipient-unavailable"; -const char STR_TERMINATE_RECIPIENT_BUSY[] = "recipient-busy"; -const char STR_TERMINATE_INSUFFICIENT_FUNDS[] = "insufficient-funds"; -const char STR_TERMINATE_NUMBER_MALFORMED[] = "number-malformed"; -const char STR_TERMINATE_NUMBER_DISALLOWED[] = "number-disallowed"; -const char STR_TERMINATE_PROTOCOL_ERROR[] = "protocol-error"; -const char STR_TERMINATE_INTERNAL_SERVER_ERROR[] = "internal-server-error"; -const char STR_TERMINATE_UNKNOWN_ERROR[] = "unknown-error"; - -// Draft view and notify messages. -const char STR_JINGLE_DRAFT_CONTENT_NAME_VIDEO[] = "video"; -const char STR_JINGLE_DRAFT_CONTENT_NAME_AUDIO[] = "audio"; -const buzz::StaticQName QN_NICK = { cricket::NS_EMPTY, "nick" }; -const buzz::StaticQName QN_TYPE = { cricket::NS_EMPTY, "type" }; -const buzz::StaticQName QN_JINGLE_DRAFT_VIEW = { NS_JINGLE_DRAFT, "view" }; -const char STR_JINGLE_DRAFT_VIEW_TYPE_NONE[] = "none"; -const char STR_JINGLE_DRAFT_VIEW_TYPE_STATIC[] = "static"; -const buzz::StaticQName QN_JINGLE_DRAFT_PARAMS = { NS_JINGLE_DRAFT, "params" }; -const buzz::StaticQName QN_JINGLE_DRAFT_STREAMS = { NS_JINGLE_DRAFT, "streams" }; -const buzz::StaticQName QN_JINGLE_DRAFT_STREAM = { NS_JINGLE_DRAFT, "stream" }; -const buzz::StaticQName QN_DISPLAY = { cricket::NS_EMPTY, "display" }; -const buzz::StaticQName QN_CNAME = { cricket::NS_EMPTY, "cname" }; -const buzz::StaticQName QN_JINGLE_DRAFT_SSRC = { NS_JINGLE_DRAFT, "ssrc" }; -const buzz::StaticQName QN_JINGLE_DRAFT_SSRC_GROUP = - { NS_JINGLE_DRAFT, "ssrc-group" }; -const buzz::StaticQName QN_SEMANTICS = { cricket::NS_EMPTY, "semantics" }; -const buzz::StaticQName QN_JINGLE_LEGACY_NOTIFY = { NS_JINGLE_DRAFT, "notify" }; -const buzz::StaticQName QN_JINGLE_LEGACY_SOURCE = { NS_JINGLE_DRAFT, "source" }; - -const buzz::StaticQName QN_GINGLE_RAW_TRANSPORT = { NS_GINGLE_RAW, "transport" }; -const buzz::StaticQName QN_GINGLE_RAW_CHANNEL = { NS_GINGLE_RAW, "channel" }; - -// old stuff -#ifdef FEATURE_ENABLE_VOICEMAIL -const char NS_VOICEMAIL[] = "http://www.google.com/session/voicemail"; -const buzz::StaticQName QN_VOICEMAIL_REGARDING = { NS_VOICEMAIL, "regarding" }; -#endif - -} // namespace cricket diff --git a/webrtc/libjingle/session/constants.h b/webrtc/libjingle/session/constants.h deleted file mode 100644 index b9d526899..000000000 --- a/webrtc/libjingle/session/constants.h +++ /dev/null @@ -1,219 +0,0 @@ -/* - * Copyright 2004 The WebRTC Project Authors. All rights reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#ifndef WEBRTC_LIBJINGLE_SESSION_CONSTANTS_H_ -#define WEBRTC_LIBJINGLE_SESSION_CONSTANTS_H_ - -#include - -#include "webrtc/libjingle/xmllite/qname.h" - -// This file contains constants related to signaling that are used in various -// classes in this directory. - -namespace cricket { - -// NS_ == namespace -// QN_ == buzz::QName (namespace + name) -// LN_ == "local name" == QName::LocalPart() -// these are useful when you need to find a tag -// that has different namespaces (like or ) - -extern const char NS_EMPTY[]; -extern const char NS_JINGLE[]; -extern const char NS_JINGLE_DRAFT[]; -extern const char NS_GINGLE[]; - -enum SignalingProtocol { - PROTOCOL_JINGLE, - PROTOCOL_GINGLE, - PROTOCOL_HYBRID, -}; - -// actions (aka Gingle or Jingle ) -extern const buzz::StaticQName QN_ACTION; -extern const char LN_INITIATOR[]; -extern const buzz::StaticQName QN_INITIATOR; -extern const buzz::StaticQName QN_CREATOR; - -extern const buzz::StaticQName QN_JINGLE; -extern const buzz::StaticQName QN_JINGLE_CONTENT; -extern const buzz::StaticQName QN_JINGLE_CONTENT_NAME; -extern const buzz::StaticQName QN_JINGLE_CONTENT_MEDIA; -extern const buzz::StaticQName QN_JINGLE_REASON; -extern const buzz::StaticQName QN_JINGLE_DRAFT_GROUP; -extern const buzz::StaticQName QN_JINGLE_DRAFT_GROUP_TYPE; -extern const char JINGLE_CONTENT_MEDIA_AUDIO[]; -extern const char JINGLE_CONTENT_MEDIA_VIDEO[]; -extern const char JINGLE_CONTENT_MEDIA_DATA[]; -extern const char JINGLE_ACTION_SESSION_INITIATE[]; -extern const char JINGLE_ACTION_SESSION_INFO[]; -extern const char JINGLE_ACTION_SESSION_ACCEPT[]; -extern const char JINGLE_ACTION_SESSION_TERMINATE[]; -extern const char JINGLE_ACTION_TRANSPORT_INFO[]; -extern const char JINGLE_ACTION_TRANSPORT_ACCEPT[]; -extern const char JINGLE_ACTION_DESCRIPTION_INFO[]; - -extern const buzz::StaticQName QN_GINGLE_SESSION; -extern const char GINGLE_ACTION_INITIATE[]; -extern const char GINGLE_ACTION_INFO[]; -extern const char GINGLE_ACTION_ACCEPT[]; -extern const char GINGLE_ACTION_REJECT[]; -extern const char GINGLE_ACTION_TERMINATE[]; -extern const char GINGLE_ACTION_CANDIDATES[]; -extern const char GINGLE_ACTION_UPDATE[]; - -extern const char LN_ERROR[]; -extern const buzz::StaticQName QN_GINGLE_REDIRECT; -extern const char STR_REDIRECT_PREFIX[]; - -// Session Contents (aka Gingle -// or Jingle ) -extern const char LN_DESCRIPTION[]; -extern const char LN_PAYLOADTYPE[]; -extern const buzz::StaticQName QN_ID; -extern const buzz::StaticQName QN_SID; -extern const buzz::StaticQName QN_NAME; -extern const buzz::StaticQName QN_CLOCKRATE; -extern const buzz::StaticQName QN_BITRATE; -extern const buzz::StaticQName QN_CHANNELS; -extern const buzz::StaticQName QN_PARAMETER; -extern const char LN_NAME[]; -extern const char LN_VALUE[]; -extern const buzz::StaticQName QN_PAYLOADTYPE_PARAMETER_NAME; -extern const buzz::StaticQName QN_PAYLOADTYPE_PARAMETER_VALUE; -extern const char PAYLOADTYPE_PARAMETER_BITRATE[]; -extern const char PAYLOADTYPE_PARAMETER_HEIGHT[]; -extern const char PAYLOADTYPE_PARAMETER_WIDTH[]; -extern const char PAYLOADTYPE_PARAMETER_FRAMERATE[]; -extern const char LN_BANDWIDTH[]; - -extern const buzz::StaticQName QN_JINGLE_RTP_CONTENT; -extern const buzz::StaticQName QN_SSRC; -extern const buzz::StaticQName QN_JINGLE_RTP_PAYLOADTYPE; -extern const buzz::StaticQName QN_JINGLE_RTP_BANDWIDTH; -extern const buzz::StaticQName QN_JINGLE_RTCP_MUX; -extern const buzz::StaticQName QN_JINGLE_RTCP_FB; -extern const buzz::StaticQName QN_SUBTYPE; -extern const buzz::StaticQName QN_JINGLE_RTP_HDREXT; -extern const buzz::StaticQName QN_URI; - -extern const buzz::StaticQName QN_JINGLE_DRAFT_SCTP_CONTENT; -extern const buzz::StaticQName QN_JINGLE_DRAFT_SCTP_STREAM; - -extern const char NS_GINGLE_AUDIO[]; -extern const buzz::StaticQName QN_GINGLE_AUDIO_CONTENT; -extern const buzz::StaticQName QN_GINGLE_AUDIO_PAYLOADTYPE; -extern const buzz::StaticQName QN_GINGLE_AUDIO_SRCID; -extern const char NS_GINGLE_VIDEO[]; -extern const buzz::StaticQName QN_GINGLE_VIDEO_CONTENT; -extern const buzz::StaticQName QN_GINGLE_VIDEO_PAYLOADTYPE; -extern const buzz::StaticQName QN_GINGLE_VIDEO_SRCID; -extern const buzz::StaticQName QN_GINGLE_VIDEO_BANDWIDTH; - -// Crypto support. -extern const buzz::StaticQName QN_ENCRYPTION; -extern const buzz::StaticQName QN_ENCRYPTION_REQUIRED; -extern const buzz::StaticQName QN_CRYPTO; -extern const buzz::StaticQName QN_GINGLE_AUDIO_CRYPTO_USAGE; -extern const buzz::StaticQName QN_GINGLE_VIDEO_CRYPTO_USAGE; -extern const buzz::StaticQName QN_CRYPTO_SUITE; -extern const buzz::StaticQName QN_CRYPTO_KEY_PARAMS; -extern const buzz::StaticQName QN_CRYPTO_TAG; -extern const buzz::StaticQName QN_CRYPTO_SESSION_PARAMS; - -// Transports and candidates. -extern const char LN_TRANSPORT[]; -extern const char LN_CANDIDATE[]; -extern const buzz::StaticQName QN_JINGLE_P2P_TRANSPORT; -extern const buzz::StaticQName QN_JINGLE_P2P_CANDIDATE; -extern const buzz::StaticQName QN_UFRAG; -extern const buzz::StaticQName QN_COMPONENT; -extern const buzz::StaticQName QN_PWD; -extern const buzz::StaticQName QN_IP; -extern const buzz::StaticQName QN_PORT; -extern const buzz::StaticQName QN_NETWORK; -extern const buzz::StaticQName QN_GENERATION; -extern const buzz::StaticQName QN_PRIORITY; -extern const buzz::StaticQName QN_PROTOCOL; -extern const char ICE_CANDIDATE_TYPE_PEER_STUN[]; -extern const char ICE_CANDIDATE_TYPE_SERVER_STUN[]; - -extern const buzz::StaticQName QN_FINGERPRINT; -extern const buzz::StaticQName QN_FINGERPRINT_ALGORITHM; -extern const buzz::StaticQName QN_FINGERPRINT_DIGEST; - -extern const buzz::StaticQName QN_GINGLE_P2P_TRANSPORT; -extern const buzz::StaticQName QN_GINGLE_P2P_CANDIDATE; -extern const buzz::StaticQName QN_GINGLE_P2P_UNKNOWN_CHANNEL_NAME; -extern const buzz::StaticQName QN_GINGLE_CANDIDATE; -extern const buzz::StaticQName QN_ADDRESS; -extern const buzz::StaticQName QN_USERNAME; -extern const buzz::StaticQName QN_PASSWORD; -extern const buzz::StaticQName QN_PREFERENCE; -extern const char GINGLE_CANDIDATE_TYPE_STUN[]; - -extern const buzz::StaticQName QN_GINGLE_RAW_TRANSPORT; -extern const buzz::StaticQName QN_GINGLE_RAW_CHANNEL; - -// terminate reasons and errors: see http://xmpp.org/extensions/xep-0166.html -extern const char JINGLE_ERROR_BAD_REQUEST[]; // like parse error -// got transport-info before session-initiate, for example -extern const char JINGLE_ERROR_OUT_OF_ORDER[]; -extern const char JINGLE_ERROR_UNKNOWN_SESSION[]; - -// Call terminate reasons from XEP-166 -extern const char STR_TERMINATE_DECLINE[]; // polite reject -extern const char STR_TERMINATE_SUCCESS[]; // polite hangup -extern const char STR_TERMINATE_ERROR[]; // something bad happened -extern const char STR_TERMINATE_INCOMPATIBLE_PARAMETERS[]; // no codecs? - -// Old terminate reasons used by cricket -extern const char STR_TERMINATE_CALL_ENDED[]; -extern const char STR_TERMINATE_RECIPIENT_UNAVAILABLE[]; -extern const char STR_TERMINATE_RECIPIENT_BUSY[]; -extern const char STR_TERMINATE_INSUFFICIENT_FUNDS[]; -extern const char STR_TERMINATE_NUMBER_MALFORMED[]; -extern const char STR_TERMINATE_NUMBER_DISALLOWED[]; -extern const char STR_TERMINATE_PROTOCOL_ERROR[]; -extern const char STR_TERMINATE_INTERNAL_SERVER_ERROR[]; -extern const char STR_TERMINATE_UNKNOWN_ERROR[]; - -// Draft view and notify messages. -extern const char STR_JINGLE_DRAFT_CONTENT_NAME_VIDEO[]; -extern const char STR_JINGLE_DRAFT_CONTENT_NAME_AUDIO[]; -extern const buzz::StaticQName QN_NICK; -extern const buzz::StaticQName QN_TYPE; -extern const buzz::StaticQName QN_JINGLE_DRAFT_VIEW; -extern const char STR_JINGLE_DRAFT_VIEW_TYPE_NONE[]; -extern const char STR_JINGLE_DRAFT_VIEW_TYPE_STATIC[]; -extern const buzz::StaticQName QN_JINGLE_DRAFT_PARAMS; -extern const buzz::StaticQName QN_WIDTH; -extern const buzz::StaticQName QN_HEIGHT; -extern const buzz::StaticQName QN_FRAMERATE; -extern const buzz::StaticQName QN_JINGLE_DRAFT_STREAM; -extern const buzz::StaticQName QN_JINGLE_DRAFT_STREAMS; -extern const buzz::StaticQName QN_DISPLAY; -extern const buzz::StaticQName QN_CNAME; -extern const buzz::StaticQName QN_JINGLE_DRAFT_SSRC; -extern const buzz::StaticQName QN_JINGLE_DRAFT_SSRC_GROUP; -extern const buzz::StaticQName QN_SEMANTICS; -extern const buzz::StaticQName QN_JINGLE_LEGACY_NOTIFY; -extern const buzz::StaticQName QN_JINGLE_LEGACY_SOURCE; - -// old stuff -#ifdef FEATURE_ENABLE_VOICEMAIL -extern const char NS_VOICEMAIL[]; -extern const buzz::StaticQName QN_VOICEMAIL_REGARDING; -#endif - -} // namespace cricket - -#endif // WEBRTC_LIBJINGLE_SESSION_CONSTANTS_H_ diff --git a/webrtc/libjingle/session/media/call.cc b/webrtc/libjingle/session/media/call.cc deleted file mode 100644 index 6a5102e5a..000000000 --- a/webrtc/libjingle/session/media/call.cc +++ /dev/null @@ -1,1134 +0,0 @@ -/* - * 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. - */ - -#include "webrtc/libjingle/session/media/call.h" - -#include - -#include "talk/media/base/constants.h" -#include "talk/media/base/screencastid.h" -#include "talk/session/media/currentspeakermonitor.h" -#include "webrtc/base/helpers.h" -#include "webrtc/base/logging.h" -#include "webrtc/base/thread.h" -#include "webrtc/base/window.h" -#include "webrtc/libjingle/session/media/mediasessionclient.h" -#include "webrtc/libjingle/session/parsing.h" - -namespace cricket { - -const uint32 MSG_CHECKAUTODESTROY = 1; -const uint32 MSG_TERMINATECALL = 2; -const uint32 MSG_PLAYDTMF = 3; - -namespace { -const int kDTMFDelay = 300; // msec -const size_t kMaxDTMFDigits = 30; -const int kSendToVoicemailTimeout = 1000*20; -const int kNoVoicemailTimeout = 1000*180; -const int kMediaMonitorInterval = 1000*15; -// In order to be the same as the server-side switching, this must be 100. -const int kAudioMonitorPollPeriodMillis = 100; - -// V is a pointer type. -template -V FindOrNull(const std::map& map, - const K& key) { - typename std::map::const_iterator it = map.find(key); - return (it != map.end()) ? it->second : NULL; -} - - -bool ContentContainsCrypto(const cricket::ContentInfo* content) { - if (content != NULL) { - const cricket::MediaContentDescription* desc = - static_cast( - content->description); - if (!desc || desc->cryptos().empty()) { - return false; - } - } - return true; -} - -} - -AudioSourceProxy::AudioSourceProxy(Call* call) - : call_(call) { - call_->SignalAudioMonitor.connect(this, &AudioSourceProxy::OnAudioMonitor); - call_->SignalMediaStreamsUpdate.connect( - this, &AudioSourceProxy::OnMediaStreamsUpdate); -} - -void AudioSourceProxy::OnAudioMonitor(Call* call, const AudioInfo& info) { - SignalAudioMonitor(this, info); -} - -void AudioSourceProxy::OnMediaStreamsUpdate(Call* call, Session* session, - const MediaStreams& added, const MediaStreams& removed) { - SignalMediaStreamsUpdate(this, session, added, removed); -} - -Call::Call(MediaSessionClient* session_client) - : id_(rtc::CreateRandomId()), - session_client_(session_client), - has_video_(false), - has_data_(false), - muted_(false), - video_muted_(false), - send_to_voicemail_(true), - playing_dtmf_(false) { - audio_source_proxy_.reset(new AudioSourceProxy(this)); -} - -Call::~Call() { - while (media_session_map_.begin() != media_session_map_.end()) { - Session* session = media_session_map_.begin()->second.session; - RemoveSession(session); - session_client_->session_manager()->DestroySession(session); - } - rtc::Thread::Current()->Clear(this); -} - -Session* Call::InitiateSession(const buzz::Jid& to, - const buzz::Jid& initiator, - const CallOptions& options) { - std::string id; - std::string initiator_name = initiator.Str(); - return InternalInitiateSession(id, to, initiator_name, options); -} - -Session *Call::InitiateSession(const std::string& id, - const buzz::Jid& to, - const CallOptions& options) { - std::string initiator_name; - return InternalInitiateSession(id, to, initiator_name, options); -} - -void Call::IncomingSession(Session* session, const SessionDescription* offer) { - AddSession(session, offer); - - // Make sure the session knows about the incoming ssrcs. This needs to be done - // prior to the SignalSessionState call, because that may trigger handling of - // these new SSRCs, so they need to be registered before then. - UpdateRemoteMediaStreams(session, offer->contents(), false); - - // Missed the first state, the initiate, which is needed by - // call_client. - SignalSessionState(this, session, Session::STATE_RECEIVEDINITIATE); -} - -void Call::AcceptSession(Session* session, - const cricket::CallOptions& options) { - MediaSessionMap::iterator it = media_session_map_.find(session->id()); - if (it != media_session_map_.end()) { - const SessionDescription* answer = session_client_->CreateAnswer( - session->remote_description(), options); - it->second.session->Accept(answer); - } -} - -void Call::RejectSession(Session* session) { - // Assume polite decline. - MediaSessionMap::iterator it = media_session_map_.find(session->id()); - if (it != media_session_map_.end()) - it->second.session->Reject(STR_TERMINATE_DECLINE); -} - -void Call::TerminateSession(Session* session) { - MediaSessionMap::iterator it = media_session_map_.find(session->id()); - if (it != media_session_map_.end()) { - // Assume polite terminations. - it->second.session->Terminate(); - } -} - -void Call::Terminate() { - // Copy the list so that we can iterate over it in a stable way - std::vector sessions = this->sessions(); - - // There may be more than one session to terminate - std::vector::iterator it; - for (it = sessions.begin(); it != sessions.end(); ++it) { - TerminateSession(*it); - } -} - -bool Call::SendViewRequest(Session* session, - const ViewRequest& view_request) { - StaticVideoViews::const_iterator it; - for (it = view_request.static_video_views.begin(); - it != view_request.static_video_views.end(); ++it) { - bool found = false; - MediaStreams* recv_streams = GetMediaStreams(session); - if (recv_streams) - found = recv_streams->GetVideoStream(it->selector, nullptr); - if (!found) { - LOG(LS_WARNING) << "Trying to send view request for (" - << it->selector.ssrc << ", '" - << it->selector.groupid << "', '" - << it->selector.streamid << "'" - << ") is not in the local streams."; - return false; - } - } - - XmlElements elems; - WriteError error; - if (!WriteJingleViewRequest(CN_VIDEO, view_request, &elems, &error)) { - LOG(LS_ERROR) << "Couldn't write out view request: " << error.text; - return false; - } - - return session->SendInfoMessage(elems, session->remote_name()); -} - -void Call::SetVideoRenderer(Session* session, uint32 ssrc, - VideoRenderer* renderer) { - VideoChannel* video_channel = GetVideoChannel(session); - if (video_channel) { - video_channel->SetRenderer(ssrc, renderer); - LOG(LS_INFO) << "Set renderer of ssrc " << ssrc - << " to " << renderer << "."; - } else { - LOG(LS_INFO) << "Failed to set renderer of ssrc " << ssrc << "."; - } -} - -void Call::OnMessage(rtc::Message* message) { - switch (message->message_id) { - case MSG_CHECKAUTODESTROY: - // If no more sessions for this call, delete it - if (media_session_map_.empty()) - session_client_->DestroyCall(this); - break; - case MSG_TERMINATECALL: - // Signal to the user that a timeout has happened and the call should - // be sent to voicemail. - if (send_to_voicemail_) { - SignalSetupToCallVoicemail(); - } - - // Callee didn't answer - terminate call - Terminate(); - break; - case MSG_PLAYDTMF: - ContinuePlayDTMF(); - } -} - -std::vector Call::sessions() { - std::vector sessions; - MediaSessionMap::iterator it; - for (it = media_session_map_.begin(); it != media_session_map_.end(); ++it) - sessions.push_back(it->second.session); - - return sessions; -} - -bool Call::AddSession(Session* session, const SessionDescription* offer) { - bool succeeded = true; - MediaSession media_session; - media_session.session = session; - media_session.voice_channel = NULL; - media_session.video_channel = NULL; - media_session.data_channel = NULL; - media_session.recv_streams = NULL; - - const ContentInfo* audio_offer = GetFirstAudioContent(offer); - const ContentInfo* video_offer = GetFirstVideoContent(offer); - const ContentInfo* data_offer = GetFirstDataContent(offer); - has_video_ = (video_offer != NULL); - has_data_ = (data_offer != NULL); - - ASSERT(audio_offer != NULL); - // Create voice channel and start a media monitor. - media_session.voice_channel = - session_client_->channel_manager()->CreateVoiceChannel( - session, audio_offer->name, has_video_, AudioOptions()); - // voice_channel can be NULL in case of NullVoiceEngine. - if (media_session.voice_channel) { - media_session.voice_channel->SignalMediaMonitor.connect( - this, &Call::OnMediaMonitor); - media_session.voice_channel->StartMediaMonitor(kMediaMonitorInterval); - } else { - succeeded = false; - } - - // If desired, create video channel and start a media monitor. - if (has_video_ && succeeded) { - media_session.video_channel = - session_client_->channel_manager()->CreateVideoChannel( - session, - video_offer->name, - true, - VideoOptions(), - media_session.voice_channel); - // video_channel can be NULL in case of NullVideoEngine. - if (media_session.video_channel) { - media_session.video_channel->SignalMediaMonitor.connect( - this, &Call::OnMediaMonitor); - media_session.video_channel->StartMediaMonitor(kMediaMonitorInterval); - } else { - succeeded = false; - } - } - - // If desired, create data channel. - if (has_data_ && succeeded) { - const DataContentDescription* data = GetFirstDataContentDescription(offer); - if (data == NULL) { - succeeded = false; - } else { - DataChannelType data_channel_type = DCT_RTP; - if ((data->protocol() == kMediaProtocolSctp) || - (data->protocol() == kMediaProtocolDtlsSctp)) { - data_channel_type = DCT_SCTP; - } - - bool rtcp = false; - media_session.data_channel = - session_client_->channel_manager()->CreateDataChannel( - session, data_offer->name, rtcp, data_channel_type); - if (media_session.data_channel) { - media_session.data_channel->SignalDataReceived.connect( - this, &Call::OnDataReceived); - } else { - succeeded = false; - } - } - } - - if (succeeded) { - // Add session to list, create channels for this session. - media_session.recv_streams = new MediaStreams; - media_session_map_[session->id()] = media_session; - session->SignalState.connect(this, &Call::OnSessionState); - session->SignalError.connect(this, &Call::OnSessionError); - session->SignalInfoMessage.connect( - this, &Call::OnSessionInfoMessage); - session->SignalRemoteDescriptionUpdate.connect( - this, &Call::OnRemoteDescriptionUpdate); - session->SignalReceivedTerminateReason - .connect(this, &Call::OnReceivedTerminateReason); - - // If this call has the focus, enable this session's channels. - if (session_client_->GetFocus() == this) { - EnableSessionChannels(session, true); - } - - // Signal client. - SignalAddSession(this, session); - } - - return succeeded; -} - -void Call::RemoveSession(Session* session) { - MediaSessionMap::iterator it = media_session_map_.find(session->id()); - if (it == media_session_map_.end()) - return; - - // Remove all the screencasts, if they haven't been already. - while (!it->second.started_screencasts.empty()) { - uint32 ssrc = it->second.started_screencasts.begin()->first; - if (!StopScreencastWithoutSendingUpdate(it->second.session, ssrc)) { - LOG(LS_ERROR) << "Unable to stop screencast with ssrc " << ssrc; - ASSERT(false); - } - } - - // Destroy video channel - VideoChannel* video_channel = it->second.video_channel; - if (video_channel != NULL) - session_client_->channel_manager()->DestroyVideoChannel(video_channel); - - // Destroy voice channel - VoiceChannel* voice_channel = it->second.voice_channel; - if (voice_channel != NULL) - session_client_->channel_manager()->DestroyVoiceChannel(voice_channel); - - // Destroy data channel - DataChannel* data_channel = it->second.data_channel; - if (data_channel != NULL) - session_client_->channel_manager()->DestroyDataChannel(data_channel); - - delete it->second.recv_streams; - media_session_map_.erase(it); - - // Destroy speaker monitor - StopSpeakerMonitor(session); - - // Signal client - SignalRemoveSession(this, session); - - // The call auto destroys when the last session is removed - rtc::Thread::Current()->Post(this, MSG_CHECKAUTODESTROY); -} - -VoiceChannel* Call::GetVoiceChannel(Session* session) const { - MediaSessionMap::const_iterator it = media_session_map_.find(session->id()); - return (it != media_session_map_.end()) ? it->second.voice_channel : NULL; -} - -VideoChannel* Call::GetVideoChannel(Session* session) const { - MediaSessionMap::const_iterator it = media_session_map_.find(session->id()); - return (it != media_session_map_.end()) ? it->second.video_channel : NULL; -} - -DataChannel* Call::GetDataChannel(Session* session) const { - MediaSessionMap::const_iterator it = media_session_map_.find(session->id()); - return (it != media_session_map_.end()) ? it->second.data_channel : NULL; -} - -MediaStreams* Call::GetMediaStreams(Session* session) const { - MediaSessionMap::const_iterator it = media_session_map_.find(session->id()); - return (it != media_session_map_.end()) ? it->second.recv_streams : NULL; -} - -void Call::EnableChannels(bool enable) { - MediaSessionMap::iterator it; - for (it = media_session_map_.begin(); it != media_session_map_.end(); ++it) { - EnableSessionChannels(it->second.session, enable); - } -} - -void Call::EnableSessionChannels(Session* session, bool enable) { - MediaSessionMap::iterator it = media_session_map_.find(session->id()); - if (it == media_session_map_.end()) - return; - - VoiceChannel* voice_channel = it->second.voice_channel; - VideoChannel* video_channel = it->second.video_channel; - DataChannel* data_channel = it->second.data_channel; - if (voice_channel != NULL) - voice_channel->Enable(enable); - if (video_channel != NULL) - video_channel->Enable(enable); - if (data_channel != NULL) - data_channel->Enable(enable); -} - -void Call::Mute(bool mute) { - muted_ = mute; - MediaSessionMap::iterator it; - for (it = media_session_map_.begin(); it != media_session_map_.end(); ++it) { - if (it->second.voice_channel != NULL) - it->second.voice_channel->MuteStream(0, mute); - } -} - -void Call::MuteVideo(bool mute) { - video_muted_ = mute; - MediaSessionMap::iterator it; - for (it = media_session_map_.begin(); it != media_session_map_.end(); ++it) { - if (it->second.video_channel != NULL) - it->second.video_channel->MuteStream(0, mute); - } -} - -bool Call::SendData(Session* session, - const SendDataParams& params, - const rtc::Buffer& payload, - SendDataResult* result) { - DataChannel* data_channel = GetDataChannel(session); - if (!data_channel) { - LOG(LS_WARNING) << "Could not send data: no data channel."; - return false; - } - - return data_channel->SendData(params, payload, result); -} - -void Call::PressDTMF(int event) { - // Queue up this digit - if (queued_dtmf_.size() < kMaxDTMFDigits) { - LOG(LS_INFO) << "Call::PressDTMF(" << event << ")"; - - queued_dtmf_.push_back(event); - - if (!playing_dtmf_) { - ContinuePlayDTMF(); - } - } -} - -cricket::VideoFormat ScreencastFormatFromFps(int fps) { - // The capturer pretty much ignore this, but just in case we give it - // a resolution big enough to cover any expected desktop. In any - // case, it can't be 0x0, or the CaptureManager will fail to use it. - return cricket::VideoFormat( - 1, 1, - cricket::VideoFormat::FpsToInterval(fps), - cricket::FOURCC_ANY); -} - -bool Call::StartScreencast(Session* session, - const std::string& streamid, uint32 ssrc, - const ScreencastId& screenid, int fps) { - MediaSessionMap::iterator it = media_session_map_.find(session->id()); - if (it == media_session_map_.end()) { - return false; - } - - VideoChannel *video_channel = GetVideoChannel(session); - if (!video_channel) { - LOG(LS_WARNING) << "Cannot add screencast" - << " because there is no video channel."; - return false; - } - - VideoCapturer* capturer = session_client_->channel_manager()-> - CreateScreenCapturer(screenid); - if (!capturer) { - LOG(LS_WARNING) << "Could not create screencast capturer."; - return false; - } - - if (!video_channel->AddScreencast(ssrc, capturer)) { - delete capturer; - LOG(LS_WARNING) << "Could not add screencast capturer."; - return false; - } - - VideoFormat format = ScreencastFormatFromFps(fps); - if (!session_client_->channel_manager()->StartVideoCapture( - capturer, format)) { - LOG(LS_WARNING) << "Could not start video capture."; - video_channel->RemoveScreencast(ssrc); - return false; - } - - if (!video_channel->SetCapturer(ssrc, capturer)) { - LOG(LS_WARNING) << "Could not start sending screencast."; - session_client_->channel_manager()->StopVideoCapture( - capturer, ScreencastFormatFromFps(fps)); - video_channel->RemoveScreencast(ssrc); - } - - // TODO(pthatcher): Once the CaptureManager has a nicer interface - // for removing captures (such as having StartCapture return a - // handle), remove this StartedCapture stuff. - it->second.started_screencasts.insert( - std::make_pair(ssrc, StartedCapture(capturer, format))); - - // TODO(pthatcher): Verify we aren't re-using an existing id or - // ssrc. - StreamParams stream; - stream.id = streamid; - stream.ssrcs.push_back(ssrc); - VideoContentDescription* video = CreateVideoStreamUpdate(stream); - - // TODO(pthatcher): Wait until view request before sending video. - video_channel->SetLocalContent(video, CA_UPDATE, NULL); - SendVideoStreamUpdate(session, video); - return true; -} - -bool Call::StopScreencast(Session* session, - const std::string& streamid, uint32 ssrc) { - if (!StopScreencastWithoutSendingUpdate(session, ssrc)) { - return false; - } - - VideoChannel *video_channel = GetVideoChannel(session); - if (!video_channel) { - LOG(LS_WARNING) << "Cannot add screencast" - << " because there is no video channel."; - return false; - } - - StreamParams stream; - stream.id = streamid; - // No ssrcs - VideoContentDescription* video = CreateVideoStreamUpdate(stream); - - video_channel->SetLocalContent(video, CA_UPDATE, NULL); - SendVideoStreamUpdate(session, video); - return true; -} - -bool Call::StopScreencastWithoutSendingUpdate( - Session* session, uint32 ssrc) { - MediaSessionMap::iterator it = media_session_map_.find(session->id()); - if (it == media_session_map_.end()) { - return false; - } - - VideoChannel *video_channel = GetVideoChannel(session); - if (!video_channel) { - LOG(LS_WARNING) << "Cannot remove screencast" - << " because there is no video channel."; - return false; - } - - StartedScreencastMap::const_iterator screencast_iter = - it->second.started_screencasts.find(ssrc); - if (screencast_iter == it->second.started_screencasts.end()) { - LOG(LS_WARNING) << "Could not stop screencast " << ssrc - << " because there is no capturer."; - return false; - } - - VideoCapturer* capturer = screencast_iter->second.capturer; - VideoFormat format = screencast_iter->second.format; - video_channel->SetCapturer(ssrc, NULL); - if (!session_client_->channel_manager()->StopVideoCapture( - capturer, format)) { - LOG(LS_WARNING) << "Could not stop screencast " << ssrc - << " because could not stop capture."; - return false; - } - video_channel->RemoveScreencast(ssrc); - it->second.started_screencasts.erase(ssrc); - return true; -} - -VideoContentDescription* Call::CreateVideoStreamUpdate( - const StreamParams& stream) { - VideoContentDescription* video = new VideoContentDescription(); - video->set_multistream(true); - video->set_partial(true); - video->AddStream(stream); - return video; -} - -void Call::SendVideoStreamUpdate( - Session* session, VideoContentDescription* video) { - // Takes the ownership of |video|. - rtc::scoped_ptr description(video); - const ContentInfo* video_info = - GetFirstVideoContent(session->local_description()); - if (video_info == NULL) { - LOG(LS_WARNING) << "Cannot send stream update for video."; - return; - } - - std::vector contents; - contents.push_back( - ContentInfo(video_info->name, video_info->type, description.get())); - - session->SendDescriptionInfoMessage(contents); -} - -void Call::ContinuePlayDTMF() { - playing_dtmf_ = false; - - // Check to see if we have a queued tone - if (queued_dtmf_.size() > 0) { - playing_dtmf_ = true; - - int tone = queued_dtmf_.front(); - queued_dtmf_.pop_front(); - - LOG(LS_INFO) << "Call::ContinuePlayDTMF(" << tone << ")"; - for (MediaSessionMap::iterator it = media_session_map_.begin(); - it != media_session_map_.end(); ++it) { - if (it->second.voice_channel != NULL) { - it->second.voice_channel->PressDTMF(tone, true); - } - } - - // Post a message to play the next tone or at least clear the playing_dtmf_ - // bit. - rtc::Thread::Current()->PostDelayed(kDTMFDelay, this, MSG_PLAYDTMF); - } -} - -void Call::Join(Call* call, bool enable) { - for (MediaSessionMap::iterator it = call->media_session_map_.begin(); - it != call->media_session_map_.end(); ++it) { - // Shouldn't already exist. - ASSERT(media_session_map_.find(it->first) == media_session_map_.end()); - media_session_map_[it->first] = it->second; - - it->second.session->SignalState.connect(this, &Call::OnSessionState); - it->second.session->SignalError.connect(this, &Call::OnSessionError); - it->second.session->SignalReceivedTerminateReason - .connect(this, &Call::OnReceivedTerminateReason); - - EnableSessionChannels(it->second.session, enable); - } - - // Moved all the sessions over, so the other call should no longer have any. - call->media_session_map_.clear(); -} - -void Call::StartConnectionMonitor(Session* session, int cms) { - VoiceChannel* voice_channel = GetVoiceChannel(session); - if (voice_channel) { - voice_channel->SignalConnectionMonitor.connect(this, - &Call::OnConnectionMonitor); - voice_channel->StartConnectionMonitor(cms); - } - - VideoChannel* video_channel = GetVideoChannel(session); - if (video_channel) { - video_channel->SignalConnectionMonitor.connect(this, - &Call::OnConnectionMonitor); - video_channel->StartConnectionMonitor(cms); - } -} - -void Call::StopConnectionMonitor(Session* session) { - VoiceChannel* voice_channel = GetVoiceChannel(session); - if (voice_channel) { - voice_channel->StopConnectionMonitor(); - voice_channel->SignalConnectionMonitor.disconnect(this); - } - - VideoChannel* video_channel = GetVideoChannel(session); - if (video_channel) { - video_channel->StopConnectionMonitor(); - video_channel->SignalConnectionMonitor.disconnect(this); - } -} - -void Call::StartAudioMonitor(Session* session, int cms) { - VoiceChannel* voice_channel = GetVoiceChannel(session); - if (voice_channel) { - voice_channel->SignalAudioMonitor.connect(this, &Call::OnAudioMonitor); - voice_channel->StartAudioMonitor(cms); - } -} - -void Call::StopAudioMonitor(Session* session) { - VoiceChannel* voice_channel = GetVoiceChannel(session); - if (voice_channel) { - voice_channel->StopAudioMonitor(); - voice_channel->SignalAudioMonitor.disconnect(this); - } -} - -bool Call::IsAudioMonitorRunning(Session* session) { - VoiceChannel* voice_channel = GetVoiceChannel(session); - if (voice_channel) { - return voice_channel->IsAudioMonitorRunning(); - } else { - return false; - } -} - -void Call::StartSpeakerMonitor(Session* session) { - if (speaker_monitor_map_.find(session->id()) == speaker_monitor_map_.end()) { - if (!IsAudioMonitorRunning(session)) { - StartAudioMonitor(session, kAudioMonitorPollPeriodMillis); - } - CurrentSpeakerMonitor* speaker_monitor = - new cricket::CurrentSpeakerMonitor( - audio_source_proxy_.get(), session); - speaker_monitor->SignalUpdate.connect(this, &Call::OnSpeakerMonitor); - speaker_monitor->Start(); - speaker_monitor_map_[session->id()] = speaker_monitor; - } else { - LOG(LS_WARNING) << "Already started speaker monitor for session " - << session->id() << "."; - } -} - -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."; - } else { - CurrentSpeakerMonitor* monitor = speaker_monitor_map_[session->id()]; - monitor->Stop(); - speaker_monitor_map_.erase(session->id()); - delete monitor; - } -} - -void Call::OnConnectionMonitor(VoiceChannel* channel, - const std::vector &infos) { - SignalConnectionMonitor(this, infos); -} - -void Call::OnMediaMonitor(VoiceChannel* channel, const VoiceMediaInfo& info) { - last_voice_media_info_ = info; - SignalMediaMonitor(this, info); -} - -void Call::OnAudioMonitor(VoiceChannel* channel, const AudioInfo& info) { - SignalAudioMonitor(this, info); -} - -void Call::OnSpeakerMonitor(CurrentSpeakerMonitor* monitor, uint32 ssrc) { - Session* session = static_cast(monitor->session()); - MediaStreams* recv_streams = GetMediaStreams(session); - if (recv_streams) { - StreamParams stream; - recv_streams->GetAudioStream(StreamSelector(ssrc), &stream); - SignalSpeakerMonitor(this, session, stream); - } -} - -void Call::OnConnectionMonitor(VideoChannel* channel, - const std::vector &infos) { - SignalVideoConnectionMonitor(this, infos); -} - -void Call::OnMediaMonitor(VideoChannel* channel, const VideoMediaInfo& info) { - SignalVideoMediaMonitor(this, info); -} - -void Call::OnDataReceived(DataChannel* channel, - const ReceiveDataParams& params, - const rtc::Buffer& payload) { - SignalDataReceived(this, params, payload); -} - -uint32 Call::id() { - return id_; -} - -void Call::OnSessionState(BaseSession* base_session, BaseSession::State state) { - Session* session = static_cast(base_session); - switch (state) { - case Session::STATE_RECEIVEDACCEPT: - UpdateRemoteMediaStreams(session, - session->remote_description()->contents(), false); - session_client_->session_manager()->signaling_thread()->Clear(this, - MSG_TERMINATECALL); - break; - case Session::STATE_RECEIVEDREJECT: - case Session::STATE_RECEIVEDTERMINATE: - session_client_->session_manager()->signaling_thread()->Clear(this, - MSG_TERMINATECALL); - break; - default: - break; - } - SignalSessionState(this, session, state); -} - -void Call::OnSessionError(BaseSession* base_session, Session::Error error) { - session_client_->session_manager()->signaling_thread()->Clear(this, - MSG_TERMINATECALL); - SignalSessionError(this, static_cast(base_session), error); -} - -void Call::OnSessionInfoMessage(Session* session, - const buzz::XmlElement* action_elem) { - if (!IsJingleViewRequest(action_elem)) { - return; - } - - ViewRequest view_request; - ParseError error; - if (!ParseJingleViewRequest(action_elem, &view_request, &error)) { - LOG(LS_WARNING) << "Failed to parse view request: " << error.text; - return; - } - - VideoChannel* video_channel = GetVideoChannel(session); - if (video_channel == NULL) { - LOG(LS_WARNING) << "Ignore view request since we have no video channel."; - return; - } - - if (!video_channel->ApplyViewRequest(view_request)) { - LOG(LS_WARNING) << "Failed to ApplyViewRequest."; - } -} - -void Call::OnRemoteDescriptionUpdate(BaseSession* base_session, - const ContentInfos& updated_contents) { - Session* session = static_cast(base_session); - - const ContentInfo* audio_content = GetFirstAudioContent(updated_contents); - if (audio_content) { - const AudioContentDescription* audio_update = - static_cast(audio_content->description); - if (!audio_update->codecs().empty()) { - UpdateVoiceChannelRemoteContent(session, audio_update); - } - } - - const ContentInfo* video_content = GetFirstVideoContent(updated_contents); - if (video_content) { - const VideoContentDescription* video_update = - static_cast(video_content->description); - if (!video_update->codecs().empty()) { - UpdateVideoChannelRemoteContent(session, video_update); - } - } - - const ContentInfo* data_content = GetFirstDataContent(updated_contents); - if (data_content) { - const DataContentDescription* data_update = - static_cast(data_content->description); - if (!data_update->codecs().empty()) { - UpdateDataChannelRemoteContent(session, data_update); - } - } - - UpdateRemoteMediaStreams(session, updated_contents, true); -} - -bool Call::UpdateVoiceChannelRemoteContent( - Session* session, const AudioContentDescription* audio) { - VoiceChannel* voice_channel = GetVoiceChannel(session); - if (!voice_channel->SetRemoteContent(audio, CA_UPDATE, NULL)) { - const std::string error_desc = - "Failure in audio SetRemoteContent with CA_UPDATE"; - LOG(LS_ERROR) << error_desc; - session->SetError(BaseSession::ERROR_CONTENT, error_desc); - return false; - } - return true; -} - -bool Call::UpdateVideoChannelRemoteContent( - Session* session, const VideoContentDescription* video) { - VideoChannel* video_channel = GetVideoChannel(session); - if (!video_channel->SetRemoteContent(video, CA_UPDATE, NULL)) { - const std::string error_desc = - "Failure in video SetRemoteContent with CA_UPDATE"; - LOG(LS_ERROR) << error_desc; - session->SetError(BaseSession::ERROR_CONTENT, error_desc); - return false; - } - return true; -} - -bool Call::UpdateDataChannelRemoteContent( - Session* session, const DataContentDescription* data) { - DataChannel* data_channel = GetDataChannel(session); - if (!data_channel->SetRemoteContent(data, CA_UPDATE, NULL)) { - const std::string error_desc = - "Failure in data SetRemoteContent with CA_UPDATE"; - LOG(LS_ERROR) << error_desc; - session->SetError(BaseSession::ERROR_CONTENT, error_desc); - return false; - } - return true; -} - -void Call::UpdateRemoteMediaStreams(Session* session, - const ContentInfos& updated_contents, - bool update_channels) { - MediaStreams* recv_streams = GetMediaStreams(session); - if (!recv_streams) - return; - - cricket::MediaStreams added_streams; - cricket::MediaStreams removed_streams; - - const ContentInfo* audio_content = GetFirstAudioContent(updated_contents); - if (audio_content) { - const AudioContentDescription* audio_update = - static_cast(audio_content->description); - UpdateRecvStreams(audio_update->streams(), - update_channels ? GetVoiceChannel(session) : NULL, - recv_streams->mutable_audio(), - added_streams.mutable_audio(), - removed_streams.mutable_audio()); - } - - const ContentInfo* video_content = GetFirstVideoContent(updated_contents); - if (video_content) { - const VideoContentDescription* video_update = - static_cast(video_content->description); - UpdateRecvStreams(video_update->streams(), - update_channels ? GetVideoChannel(session) : NULL, - recv_streams->mutable_video(), - added_streams.mutable_video(), - removed_streams.mutable_video()); - } - - const ContentInfo* data_content = GetFirstDataContent(updated_contents); - if (data_content) { - const DataContentDescription* data_update = - static_cast(data_content->description); - UpdateRecvStreams(data_update->streams(), - update_channels ? GetDataChannel(session) : NULL, - recv_streams->mutable_data(), - added_streams.mutable_data(), - removed_streams.mutable_data()); - } - - if (!added_streams.empty() || !removed_streams.empty()) { - SignalMediaStreamsUpdate(this, session, added_streams, removed_streams); - } -} - -void FindStreamChanges(const std::vector& streams, - const std::vector& updates, - std::vector* added_streams, - std::vector* removed_streams) { - for (std::vector::const_iterator update = updates.begin(); - update != updates.end(); ++update) { - const StreamParams* stream = - GetStreamByIds(streams, update->groupid, update->id); - if (stream) { - if (!update->has_ssrcs()) { - removed_streams->push_back(*stream); - } - } else { - // There's a bug on reflector that will send s even - // though there is not ssrc (which means there isn't really a - // stream). To work around it, we simply ignore new s - // that don't have any ssrcs. - if (update->has_ssrcs()) { - added_streams->push_back(*update); - } - } - } -} - -void Call::UpdateRecvStreams(const std::vector& update_streams, - BaseChannel* channel, - std::vector* recv_streams, - std::vector* added_streams, - std::vector* removed_streams) { - FindStreamChanges(*recv_streams, - update_streams, added_streams, removed_streams); - AddRecvStreams(*added_streams, - channel, recv_streams); - RemoveRecvStreams(*removed_streams, - channel, recv_streams); -} - -void Call::AddRecvStreams(const std::vector& added_streams, - BaseChannel* channel, - std::vector* recv_streams) { - std::vector::const_iterator stream; - for (stream = added_streams.begin(); - stream != added_streams.end(); - ++stream) { - AddRecvStream(*stream, channel, recv_streams); - } -} - -void Call::AddRecvStream(const StreamParams& stream, - BaseChannel* channel, - std::vector* recv_streams) { - if (channel && stream.has_ssrcs()) { - channel->AddRecvStream(stream); - } - recv_streams->push_back(stream); -} - -void Call::RemoveRecvStreams(const std::vector& removed_streams, - BaseChannel* channel, - std::vector* recv_streams) { - std::vector::const_iterator stream; - for (stream = removed_streams.begin(); - stream != removed_streams.end(); - ++stream) { - RemoveRecvStream(*stream, channel, recv_streams); - } -} - -void Call::RemoveRecvStream(const StreamParams& stream, - BaseChannel* channel, - std::vector* recv_streams) { - if (channel && stream.has_ssrcs()) { - // TODO(pthatcher): Change RemoveRecvStream to take a stream argument. - channel->RemoveRecvStream(stream.first_ssrc()); - } - RemoveStreamByIds(recv_streams, stream.groupid, stream.id); -} - -void Call::OnReceivedTerminateReason(Session* session, - const std::string& reason) { - session_client_->session_manager()->signaling_thread()->Clear(this, - MSG_TERMINATECALL); - SignalReceivedTerminateReason(this, session, reason); -} - -// TODO(mdodd): Get ride of this method since all Hangouts are using a secure -// connection. -bool Call::secure() const { - if (session_client_->secure() == SEC_DISABLED) { - return false; - } - - bool ret = true; - int i = 0; - - MediaSessionMap::const_iterator it; - for (it = media_session_map_.begin(); it != media_session_map_.end(); ++it) { - LOG_F(LS_VERBOSE) << "session[" << i - << "], check local and remote descriptions"; - i++; - - if (!SessionDescriptionContainsCrypto( - it->second.session->local_description()) || - !SessionDescriptionContainsCrypto( - it->second.session->remote_description())) { - ret = false; - break; - } - } - - LOG_F(LS_VERBOSE) << "secure=" << ret; - return ret; -} - -bool Call::SessionDescriptionContainsCrypto( - const SessionDescription* sdesc) const { - if (sdesc == NULL) { - LOG_F(LS_VERBOSE) << "sessionDescription is NULL"; - return false; - } - - return ContentContainsCrypto(sdesc->GetContentByName(CN_AUDIO)) && - ContentContainsCrypto(sdesc->GetContentByName(CN_VIDEO)); -} - -Session* Call::InternalInitiateSession(const std::string& id, - const buzz::Jid& to, - const std::string& initiator_name, - const CallOptions& options) { - const SessionDescription* offer = session_client_->CreateOffer(options); - - Session* session = session_client_->CreateSession(id, this); - // Only override the initiator_name if it was manually supplied. Otherwise, - // session_client_ will supply the local jid as initiator in CreateOffer. - if (!initiator_name.empty()) { - session->set_initiator_name(initiator_name); - } - - AddSession(session, offer); - session->Initiate(to.Str(), offer); - - // After this timeout, terminate the call because the callee isn't - // answering - session_client_->session_manager()->signaling_thread()->Clear(this, - MSG_TERMINATECALL); - session_client_->session_manager()->signaling_thread()->PostDelayed( - send_to_voicemail_ ? kSendToVoicemailTimeout : kNoVoicemailTimeout, - this, MSG_TERMINATECALL); - return session; -} - -AudioSourceProxy* Call::GetAudioSourceProxy() { - return audio_source_proxy_.get(); -} - -} // namespace cricket diff --git a/webrtc/libjingle/session/media/call.h b/webrtc/libjingle/session/media/call.h deleted file mode 100644 index 48b31b6df..000000000 --- a/webrtc/libjingle/session/media/call.h +++ /dev/null @@ -1,308 +0,0 @@ -/* - * 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 WEBRTC_LIBJINGLE_SESSION_MEDIA_CALL_H_ -#define WEBRTC_LIBJINGLE_SESSION_MEDIA_CALL_H_ - -#include -#include -#include -#include - -#include "talk/media/base/mediachannel.h" -#include "talk/media/base/screencastid.h" -#include "talk/media/base/streamparams.h" -#include "talk/media/base/videocommon.h" -#include "talk/session/media/audiomonitor.h" -#include "talk/session/media/currentspeakermonitor.h" -#include "talk/session/media/mediasession.h" -#include "webrtc/base/messagequeue.h" -#include "webrtc/libjingle/session/media/mediamessages.h" -#include "webrtc/libjingle/session/sessionmanager.h" -#include "webrtc/libjingle/xmpp/jid.h" -#include "webrtc/p2p/client/socketmonitor.h" -#include "webrtc/p2p/client/socketmonitor.h" - -namespace cricket { - -struct AudioInfo; -class Call; -class MediaSessionClient; -class BaseChannel; -class VoiceChannel; -class VideoChannel; -class DataChannel; - -// Can't typedef this easily since it's forward declared as struct elsewhere. -struct CallOptions : public MediaSessionOptions { -}; - -// CurrentSpeakerMonitor used to have a dependency on Call. To remove this -// dependency, we create AudioSourceContext. CurrentSpeakerMonitor depends on -// AudioSourceContext. -// AudioSourceProxy acts as a proxy so that when SignalAudioMonitor -// in Call is triggered, SignalAudioMonitor in AudioSourceContext is triggered. -// Likewise, when OnMediaStreamsUpdate in Call is triggered, -// OnMediaStreamsUpdate in AudioSourceContext is triggered. -class AudioSourceProxy: public AudioSourceContext, public sigslot::has_slots<> { - public: - explicit AudioSourceProxy(Call* call); - - private: - void OnAudioMonitor(Call* call, const AudioInfo& info); - void OnMediaStreamsUpdate(Call* call, cricket::Session*, - const cricket::MediaStreams&, const cricket::MediaStreams&); - - Call* call_; -}; - -class Call : public rtc::MessageHandler, public sigslot::has_slots<> { - public: - explicit Call(MediaSessionClient* session_client); - ~Call(); - - // |initiator| can be empty. - Session* InitiateSession(const buzz::Jid& to, const buzz::Jid& initiator, - const CallOptions& options); - Session* InitiateSession(const std::string& id, const buzz::Jid& to, - const CallOptions& options); - 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 SetVideoRenderer(Session* session, uint32 ssrc, - VideoRenderer* renderer); - 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); - bool SendData(Session* session, - const SendDataParams& params, - const rtc::Buffer& payload, - SendDataResult* result); - void PressDTMF(int event); - bool StartScreencast(Session* session, - const std::string& stream_name, uint32 ssrc, - const ScreencastId& screenid, int fps); - bool StopScreencast(Session* session, - const std::string& stream_name, uint32 ssrc); - - std::vector sessions(); - uint32 id(); - bool has_video() const { return has_video_; } - bool has_data() const { return has_data_; } - bool muted() const { return muted_; } - bool video() const { return has_video_; } - bool secure() const; - bool video_muted() const { return video_muted_; } - const std::vector* GetDataRecvStreams(Session* session) const { - MediaStreams* recv_streams = GetMediaStreams(session); - return recv_streams ? &recv_streams->data() : NULL; - } - const std::vector* GetVideoRecvStreams(Session* session) const { - MediaStreams* recv_streams = GetMediaStreams(session); - return recv_streams ? &recv_streams->video() : NULL; - } - const std::vector* GetAudioRecvStreams(Session* session) const { - MediaStreams* recv_streams = GetMediaStreams(session); - return recv_streams ? &recv_streams->audio() : NULL; - } - VoiceChannel* GetVoiceChannel(Session* session) const; - VideoChannel* GetVideoChannel(Session* session) const; - DataChannel* GetDataChannel(Session* session) const; - // Public just for unit tests - VideoContentDescription* CreateVideoStreamUpdate(const StreamParams& stream); - // Takes ownership of video. - void SendVideoStreamUpdate(Session* session, VideoContentDescription* video); - - // Setting this to false will cause the call to have a longer timeout and - // for the SignalSetupToCallVoicemail to never fire. - void set_send_to_voicemail(bool send_to_voicemail) { - send_to_voicemail_ = send_to_voicemail; - } - bool send_to_voicemail() { return send_to_voicemail_; } - const VoiceMediaInfo& last_voice_media_info() const { - return last_voice_media_info_; - } - - // Sets a flag on the chatapp that will redirect the call to voicemail once - // the call has been terminated - sigslot::signal0<> SignalSetupToCallVoicemail; - sigslot::signal2 SignalAddSession; - sigslot::signal2 SignalRemoveSession; - sigslot::signal3 - SignalSessionState; - sigslot::signal3 - SignalSessionError; - sigslot::signal3 - SignalReceivedTerminateReason; - sigslot::signal2 &> - SignalConnectionMonitor; - sigslot::signal2 SignalMediaMonitor; - sigslot::signal2 SignalAudioMonitor; - // Empty nick on StreamParams means "unknown". - // No ssrcs in StreamParams means "no current speaker". - sigslot::signal3 SignalSpeakerMonitor; - sigslot::signal2 &> - SignalVideoConnectionMonitor; - sigslot::signal2 SignalVideoMediaMonitor; - // Gives added streams and removed streams, in that order. - sigslot::signal4 SignalMediaStreamsUpdate; - sigslot::signal3 SignalDataReceived; - - AudioSourceProxy* GetAudioSourceProxy(); - - private: - void OnMessage(rtc::Message* message); - void OnSessionState(BaseSession* base_session, BaseSession::State state); - void OnSessionError(BaseSession* base_session, BaseSession::Error error); - void OnSessionInfoMessage( - Session* session, const buzz::XmlElement* action_elem); - void OnViewRequest( - Session* session, const ViewRequest& view_request); - void OnRemoteDescriptionUpdate( - BaseSession* base_session, const ContentInfos& updated_contents); - void OnReceivedTerminateReason(Session* session, const std::string &reason); - void IncomingSession(Session* session, const SessionDescription* offer); - // Returns true on success. - bool AddSession(Session* session, const SessionDescription* offer); - void RemoveSession(Session* session); - void EnableChannels(bool enable); - void EnableSessionChannels(Session* session, bool enable); - void Join(Call* call, bool enable); - void OnConnectionMonitor(VoiceChannel* channel, - const std::vector &infos); - void OnMediaMonitor(VoiceChannel* channel, const VoiceMediaInfo& info); - void OnAudioMonitor(VoiceChannel* channel, const AudioInfo& info); - void OnSpeakerMonitor(CurrentSpeakerMonitor* monitor, uint32 ssrc); - void OnConnectionMonitor(VideoChannel* channel, - const std::vector &infos); - void OnMediaMonitor(VideoChannel* channel, const VideoMediaInfo& info); - void OnDataReceived(DataChannel* channel, - const ReceiveDataParams& params, - const rtc::Buffer& payload); - MediaStreams* GetMediaStreams(Session* session) const; - void UpdateRemoteMediaStreams(Session* session, - const ContentInfos& updated_contents, - bool update_channels); - bool UpdateVoiceChannelRemoteContent(Session* session, - const AudioContentDescription* audio); - bool UpdateVideoChannelRemoteContent(Session* session, - const VideoContentDescription* video); - bool UpdateDataChannelRemoteContent(Session* session, - const DataContentDescription* data); - void UpdateRecvStreams(const std::vector& update_streams, - BaseChannel* channel, - std::vector* recv_streams, - std::vector* added_streams, - std::vector* removed_streams); - void AddRecvStreams(const std::vector& added_streams, - BaseChannel* channel, - std::vector* recv_streams); - void AddRecvStream(const StreamParams& stream, - BaseChannel* channel, - std::vector* recv_streams); - void RemoveRecvStreams(const std::vector& removed_streams, - BaseChannel* channel, - std::vector* recv_streams); - void RemoveRecvStream(const StreamParams& stream, - BaseChannel* channel, - std::vector* recv_streams); - void ContinuePlayDTMF(); - bool StopScreencastWithoutSendingUpdate(Session* session, uint32 ssrc); - bool StopAllScreencastsWithoutSendingUpdate(Session* session); - bool SessionDescriptionContainsCrypto(const SessionDescription* sdesc) const; - Session* InternalInitiateSession(const std::string& id, - const buzz::Jid& to, - const std::string& initiator_name, - const CallOptions& options); - - uint32 id_; - MediaSessionClient* session_client_; - - struct StartedCapture { - StartedCapture(cricket::VideoCapturer* capturer, - const cricket::VideoFormat& format) : - capturer(capturer), - format(format) { - } - cricket::VideoCapturer* capturer; - cricket::VideoFormat format; - }; - typedef std::map StartedScreencastMap; - - struct MediaSession { - Session* session; - VoiceChannel* voice_channel; - VideoChannel* video_channel; - DataChannel* data_channel; - MediaStreams* recv_streams; - StartedScreencastMap started_screencasts; - }; - - // Create a map of media sessions, keyed off session->id(). - typedef std::map MediaSessionMap; - MediaSessionMap media_session_map_; - - std::map speaker_monitor_map_; - bool has_video_; - bool has_data_; - 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 - // keep a deque (doubely ended queue) of them around. While one is playing we - // set the playing_dtmf_ bit and schedule a message in XX msec to clear that - // bit or start the next tone playing. - std::deque queued_dtmf_; - bool playing_dtmf_; - - VoiceMediaInfo last_voice_media_info_; - - rtc::scoped_ptr audio_source_proxy_; - - friend class MediaSessionClient; -}; - -} // namespace cricket - -#endif // WEBRTC_LIBJINGLE_SESSION_MEDIA_CALL_H_ diff --git a/webrtc/libjingle/session/media/mediamessages.cc b/webrtc/libjingle/session/media/mediamessages.cc deleted file mode 100644 index e8ec38f1f..000000000 --- a/webrtc/libjingle/session/media/mediamessages.cc +++ /dev/null @@ -1,332 +0,0 @@ -/* - * libjingle - * Copyright 2010 Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * Documentation is in mediamessages.h. - */ - -#include "webrtc/libjingle/session/media/mediamessages.h" - -#include "webrtc/p2p/base/constants.h" -#include "webrtc/libjingle/session/media/mediasessionclient.h" -#include "webrtc/libjingle/xmllite/xmlelement.h" -#include "webrtc/base/logging.h" -#include "webrtc/base/stringencode.h" - -namespace cricket { - -namespace { - -bool ParseSsrc(const std::string& string, uint32* ssrc) { - return rtc::FromString(string, ssrc); -} - -// Builds a element according to the following spec: -// goto/jinglemuc -buzz::XmlElement* CreateViewElem(const std::string& name, - const std::string& type) { - buzz::XmlElement* view_elem = - new buzz::XmlElement(QN_JINGLE_DRAFT_VIEW, true); - view_elem->AddAttr(QN_NAME, name); - view_elem->SetAttr(QN_TYPE, type); - return view_elem; -} - -buzz::XmlElement* CreateVideoViewElem(const std::string& content_name, - const std::string& type) { - return CreateViewElem(content_name, type); -} - -buzz::XmlElement* CreateNoneVideoViewElem(const std::string& content_name) { - return CreateVideoViewElem(content_name, STR_JINGLE_DRAFT_VIEW_TYPE_NONE); -} - -buzz::XmlElement* CreateStaticVideoViewElem(const std::string& content_name, - const StaticVideoView& view) { - buzz::XmlElement* view_elem = - CreateVideoViewElem(content_name, STR_JINGLE_DRAFT_VIEW_TYPE_STATIC); - AddXmlAttr(view_elem, QN_SSRC, view.selector.ssrc); - - buzz::XmlElement* params_elem = new buzz::XmlElement(QN_JINGLE_DRAFT_PARAMS); - AddXmlAttr(params_elem, QN_WIDTH, view.width); - AddXmlAttr(params_elem, QN_HEIGHT, view.height); - AddXmlAttr(params_elem, QN_FRAMERATE, view.framerate); - AddXmlAttr(params_elem, QN_PREFERENCE, view.preference); - view_elem->AddElement(params_elem); - - return view_elem; -} - -} // namespace - -bool IsJingleViewRequest(const buzz::XmlElement* action_elem) { - return action_elem->FirstNamed(QN_JINGLE_DRAFT_VIEW) != NULL; -} - -bool ParseStaticVideoView(const buzz::XmlElement* view_elem, - StaticVideoView* view, - ParseError* error) { - uint32 ssrc; - if (!ParseSsrc(view_elem->Attr(QN_SSRC), &ssrc)) { - return BadParse("Invalid or missing view ssrc.", error); - } - view->selector = StreamSelector(ssrc); - - const buzz::XmlElement* params_elem = - view_elem->FirstNamed(QN_JINGLE_DRAFT_PARAMS); - if (params_elem) { - view->width = GetXmlAttr(params_elem, QN_WIDTH, 0); - view->height = GetXmlAttr(params_elem, QN_HEIGHT, 0); - view->framerate = GetXmlAttr(params_elem, QN_FRAMERATE, 0); - view->preference = GetXmlAttr(params_elem, QN_PREFERENCE, 0); - } else { - return BadParse("Missing view params.", error); - } - - return true; -} - -bool ParseJingleViewRequest(const buzz::XmlElement* action_elem, - ViewRequest* view_request, - ParseError* error) { - for (const buzz::XmlElement* view_elem = - action_elem->FirstNamed(QN_JINGLE_DRAFT_VIEW); - view_elem != NULL; - view_elem = view_elem->NextNamed(QN_JINGLE_DRAFT_VIEW)) { - std::string type = view_elem->Attr(QN_TYPE); - if (STR_JINGLE_DRAFT_VIEW_TYPE_NONE == type) { - view_request->static_video_views.clear(); - return true; - } else if (STR_JINGLE_DRAFT_VIEW_TYPE_STATIC == type) { - StaticVideoView static_video_view(StreamSelector(0), 0, 0, 0); - if (!ParseStaticVideoView(view_elem, &static_video_view, error)) { - return false; - } - view_request->static_video_views.push_back(static_video_view); - } else { - LOG(LS_INFO) << "Ingnoring unknown view type: " << type; - } - } - return true; -} - -bool WriteJingleViewRequest(const std::string& content_name, - const ViewRequest& request, - XmlElements* elems, - WriteError* error) { - if (request.static_video_views.empty()) { - elems->push_back(CreateNoneVideoViewElem(content_name)); - } else { - for (StaticVideoViews::const_iterator view = - request.static_video_views.begin(); - view != request.static_video_views.end(); ++view) { - elems->push_back(CreateStaticVideoViewElem(content_name, *view)); - } - } - return true; -} - -bool ParseSsrcAsLegacyStream(const buzz::XmlElement* desc_elem, - std::vector* streams, - ParseError* error) { - const std::string ssrc_str = desc_elem->Attr(QN_SSRC); - if (!ssrc_str.empty()) { - uint32 ssrc; - if (!ParseSsrc(ssrc_str, &ssrc)) { - return BadParse("Missing or invalid ssrc.", error); - } - - streams->push_back(StreamParams::CreateLegacy(ssrc)); - } - return true; -} - -bool ParseSsrcs(const buzz::XmlElement* parent_elem, - std::vector* ssrcs, - ParseError* error) { - for (const buzz::XmlElement* ssrc_elem = - parent_elem->FirstNamed(QN_JINGLE_DRAFT_SSRC); - ssrc_elem != NULL; - ssrc_elem = ssrc_elem->NextNamed(QN_JINGLE_DRAFT_SSRC)) { - uint32 ssrc; - if (!ParseSsrc(ssrc_elem->BodyText(), &ssrc)) { - return BadParse("Missing or invalid ssrc.", error); - } - - ssrcs->push_back(ssrc); - } - return true; -} - -bool ParseSsrcGroups(const buzz::XmlElement* parent_elem, - std::vector* ssrc_groups, - ParseError* error) { - for (const buzz::XmlElement* group_elem = - parent_elem->FirstNamed(QN_JINGLE_DRAFT_SSRC_GROUP); - group_elem != NULL; - group_elem = group_elem->NextNamed(QN_JINGLE_DRAFT_SSRC_GROUP)) { - std::string semantics = group_elem->Attr(QN_SEMANTICS); - std::vector ssrcs; - if (!ParseSsrcs(group_elem, &ssrcs, error)) { - return false; - } - ssrc_groups->push_back(SsrcGroup(semantics, ssrcs)); - } - return true; -} - -bool ParseJingleStream(const buzz::XmlElement* stream_elem, - std::vector* streams, - ParseError* error) { - StreamParams stream; - // We treat the nick as a stream groupid. - stream.groupid = stream_elem->Attr(QN_NICK); - stream.id = stream_elem->Attr(QN_NAME); - stream.type = stream_elem->Attr(QN_TYPE); - stream.display = stream_elem->Attr(QN_DISPLAY); - stream.cname = stream_elem->Attr(QN_CNAME); - if (!ParseSsrcs(stream_elem, &(stream.ssrcs), error)) { - return false; - } - std::vector ssrc_groups; - if (!ParseSsrcGroups(stream_elem, &(stream.ssrc_groups), error)) { - return false; - } - streams->push_back(stream); - return true; -} - -bool ParseJingleRtpHeaderExtensions(const buzz::XmlElement* parent_elem, - std::vector* hdrexts, - ParseError* error) { - for (const buzz::XmlElement* hdrext_elem = - parent_elem->FirstNamed(QN_JINGLE_RTP_HDREXT); - hdrext_elem != NULL; - hdrext_elem = hdrext_elem->NextNamed(QN_JINGLE_RTP_HDREXT)) { - std::string uri = hdrext_elem->Attr(QN_URI); - int id = GetXmlAttr(hdrext_elem, QN_ID, 0); - if (id <= 0) { - return BadParse("Invalid RTP header extension id.", error); - } - hdrexts->push_back(RtpHeaderExtension(uri, id)); - } - return true; -} - -bool HasJingleStreams(const buzz::XmlElement* desc_elem) { - const buzz::XmlElement* streams_elem = - desc_elem->FirstNamed(QN_JINGLE_DRAFT_STREAMS); - return (streams_elem != NULL); -} - -bool ParseJingleStreams(const buzz::XmlElement* desc_elem, - std::vector* streams, - ParseError* error) { - const buzz::XmlElement* streams_elem = - desc_elem->FirstNamed(QN_JINGLE_DRAFT_STREAMS); - if (streams_elem == NULL) { - return BadParse("Missing streams element.", error); - } - for (const buzz::XmlElement* stream_elem = - streams_elem->FirstNamed(QN_JINGLE_DRAFT_STREAM); - stream_elem != NULL; - stream_elem = stream_elem->NextNamed(QN_JINGLE_DRAFT_STREAM)) { - if (!ParseJingleStream(stream_elem, streams, error)) { - return false; - } - } - return true; -} - -void WriteSsrcs(const std::vector& ssrcs, - buzz::XmlElement* parent_elem) { - for (std::vector::const_iterator ssrc = ssrcs.begin(); - ssrc != ssrcs.end(); ++ssrc) { - buzz::XmlElement* ssrc_elem = - new buzz::XmlElement(QN_JINGLE_DRAFT_SSRC, false); - SetXmlBody(ssrc_elem, *ssrc); - - parent_elem->AddElement(ssrc_elem); - } -} - -void WriteSsrcGroups(const std::vector& groups, - buzz::XmlElement* parent_elem) { - for (std::vector::const_iterator group = groups.begin(); - group != groups.end(); ++group) { - buzz::XmlElement* group_elem = - new buzz::XmlElement(QN_JINGLE_DRAFT_SSRC_GROUP, false); - AddXmlAttrIfNonEmpty(group_elem, QN_SEMANTICS, group->semantics); - WriteSsrcs(group->ssrcs, group_elem); - - parent_elem->AddElement(group_elem); - } -} - -void WriteJingleStream(const StreamParams& stream, - buzz::XmlElement* parent_elem) { - buzz::XmlElement* stream_elem = - new buzz::XmlElement(QN_JINGLE_DRAFT_STREAM, false); - // We treat the nick as a stream groupid. - AddXmlAttrIfNonEmpty(stream_elem, QN_NICK, stream.groupid); - AddXmlAttrIfNonEmpty(stream_elem, QN_NAME, stream.id); - AddXmlAttrIfNonEmpty(stream_elem, QN_TYPE, stream.type); - AddXmlAttrIfNonEmpty(stream_elem, QN_DISPLAY, stream.display); - AddXmlAttrIfNonEmpty(stream_elem, QN_CNAME, stream.cname); - WriteSsrcs(stream.ssrcs, stream_elem); - WriteSsrcGroups(stream.ssrc_groups, stream_elem); - - parent_elem->AddElement(stream_elem); -} - -void WriteJingleStreams(const std::vector& streams, - buzz::XmlElement* parent_elem) { - buzz::XmlElement* streams_elem = - new buzz::XmlElement(QN_JINGLE_DRAFT_STREAMS, true); - for (std::vector::const_iterator stream = streams.begin(); - stream != streams.end(); ++stream) { - WriteJingleStream(*stream, streams_elem); - } - - parent_elem->AddElement(streams_elem); -} - -void WriteJingleRtpHeaderExtensions( - const std::vector& hdrexts, - buzz::XmlElement* parent_elem) { - for (std::vector::const_iterator hdrext = hdrexts.begin(); - hdrext != hdrexts.end(); ++hdrext) { - buzz::XmlElement* hdrext_elem = - new buzz::XmlElement(QN_JINGLE_RTP_HDREXT, false); - AddXmlAttr(hdrext_elem, QN_URI, hdrext->uri); - AddXmlAttr(hdrext_elem, QN_ID, hdrext->id); - parent_elem->AddElement(hdrext_elem); - } -} - - -} // namespace cricket diff --git a/webrtc/libjingle/session/media/mediamessages.h b/webrtc/libjingle/session/media/mediamessages.h deleted file mode 100644 index b7943f675..000000000 --- a/webrtc/libjingle/session/media/mediamessages.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - * libjingle - * Copyright 2010 Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * A collection of functions and types for serializing and - * deserializing Jingle session messages related to media. - * Specificially, the and messages. They are not yet - * standardized, but their current documentation can be found at: - * goto/jinglemuc - */ - -#ifndef WEBRTC_LIBJINGLE_SESSION_MEDIA_MEDIAMESSAGES_H_ -#define WEBRTC_LIBJINGLE_SESSION_MEDIA_MEDIAMESSAGES_H_ - -#include -#include - -#include "talk/media/base/mediachannel.h" // For RtpHeaderExtension -#include "talk/media/base/streamparams.h" -#include "webrtc/base/basictypes.h" -#include "webrtc/libjingle/session/parsing.h" -#include "webrtc/p2p/base/sessiondescription.h" - -namespace cricket { - -// If the parent element (usually ) is a jingle view. -bool IsJingleViewRequest(const buzz::XmlElement* action_elem); - -// Parses a view request from the parent element (usually -// ). If it fails, it returns false and fills an error -// message. -bool ParseJingleViewRequest(const buzz::XmlElement* action_elem, - ViewRequest* view_request, - ParseError* error); - -// Serializes a view request to XML. If it fails, returns false and -// fills in an error message. -bool WriteJingleViewRequest(const std::string& content_name, - const ViewRequest& view, - XmlElements* elems, - WriteError* error); - -// TODO(pthatcher): Get rid of legacy source notify and replace with -// description-info as soon as reflector is capable of sending it. -bool IsSourcesNotify(const buzz::XmlElement* action_elem); - -// If the given elem has . -bool HasJingleStreams(const buzz::XmlElement* desc_elem); - -// Parses streams from a jingle . If it fails, returns -// false and fills an error message. -bool ParseJingleStreams(const buzz::XmlElement* desc_elem, - std::vector* streams, - ParseError* error); - -// Write a element to the parent_elem. -void WriteJingleStreams(const std::vector& streams, - buzz::XmlElement* parent_elem); - -// Parses rtp header extensions from a jingle . If it -// fails, returns false and fills an error message. -bool ParseJingleRtpHeaderExtensions( - const buzz::XmlElement* desc_elem, - std::vector* hdrexts, - ParseError* error); - -// Writes elements to the parent_elem. -void WriteJingleRtpHeaderExtensions( - const std::vector& hdrexts, - buzz::XmlElement* parent_elem); - -} // namespace cricket - -#endif // WEBRTC_LIBJINGLE_SESSION_MEDIA_MEDIAMESSAGES_H_ diff --git a/webrtc/libjingle/session/media/mediamessages_unittest.cc b/webrtc/libjingle/session/media/mediamessages_unittest.cc deleted file mode 100644 index 6d8fb4b6d..000000000 --- a/webrtc/libjingle/session/media/mediamessages_unittest.cc +++ /dev/null @@ -1,363 +0,0 @@ -/* - * 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. - */ - -#include "webrtc/libjingle/session/media/mediamessages.h" - -#include -#include - -#include "webrtc/p2p/base/constants.h" -#include "webrtc/libjingle/session/media/mediasessionclient.h" -#include "webrtc/libjingle/xmllite/xmlelement.h" -#include "webrtc/base/gunit.h" -#include "webrtc/base/scoped_ptr.h" - -// Unit tests for mediamessages.cc. - -namespace cricket { - -namespace { - -static const char kViewVideoNoneXml[] = - ""; - -class MediaMessagesTest : public testing::Test { - public: - // CreateMediaSessionDescription uses a static variable cricket::NS_JINGLE_RTP - // defined in another file and cannot be used to initialize another static - // variable (http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.14) - MediaMessagesTest() - : remote_description_(CreateMediaSessionDescription("audio1", "video1")) { - } - - protected: - static std::string ViewVideoStaticVgaXml(const std::string& ssrc) { - return "" - "" - ""; - } - - static cricket::StreamParams CreateStream(const std::string& nick, - const std::string& name, - uint32 ssrc1, - uint32 ssrc2, - const std::string& semantics, - const std::string& type, - const std::string& display) { - StreamParams stream; - stream.groupid = nick; - stream.id = name; - stream.ssrcs.push_back(ssrc1); - stream.ssrcs.push_back(ssrc2); - stream.ssrc_groups.push_back( - cricket::SsrcGroup(semantics, stream.ssrcs)); - stream.type = type; - stream.display = display; - return stream; - } - - static std::string StreamsXml(const std::string& stream1, - const std::string& stream2) { - return "" - + stream1 - + stream2 + - ""; - } - - - static std::string StreamXml(const std::string& nick, - const std::string& name, - const std::string& ssrc1, - const std::string& ssrc2, - const std::string& semantics, - const std::string& type, - const std::string& display) { - return "" - "" + ssrc1 + "" - "" + ssrc2 + "" - "" - "" + ssrc1 + "" - "" + ssrc2 + "" - "" - ""; - } - - static std::string HeaderExtensionsXml(const std::string& hdrext1, - const std::string& hdrext2) { - return "" - + hdrext1 - + hdrext2 + - ""; - } - - static std::string HeaderExtensionXml(const std::string& uri, - const std::string& id) { - return ""; - } - - static cricket::SessionDescription* CreateMediaSessionDescription( - const std::string& audio_content_name, - const std::string& video_content_name) { - cricket::SessionDescription* desc = new cricket::SessionDescription(); - desc->AddContent(audio_content_name, cricket::NS_JINGLE_RTP, - new cricket::AudioContentDescription()); - desc->AddContent(video_content_name, cricket::NS_JINGLE_RTP, - new cricket::VideoContentDescription()); - return desc; - } - - size_t ClearXmlElements(cricket::XmlElements* elements) { - size_t size = elements->size(); - for (size_t i = 0; i < size; i++) { - delete elements->at(i); - } - elements->clear(); - return size; - } - - rtc::scoped_ptr remote_description_; -}; - -} // anonymous namespace - -// Test serializing/deserializing an empty message. -TEST_F(MediaMessagesTest, ViewNoneToFromXml) { - buzz::XmlElement* expected_view_elem = - buzz::XmlElement::ForStr(kViewVideoNoneXml); - rtc::scoped_ptr action_elem( - new buzz::XmlElement(QN_JINGLE)); - - EXPECT_FALSE(cricket::IsJingleViewRequest(action_elem.get())); - action_elem->AddElement(expected_view_elem); - EXPECT_TRUE(cricket::IsJingleViewRequest(action_elem.get())); - - cricket::ViewRequest view_request; - cricket::XmlElements actual_view_elems; - cricket::WriteError error; - - ASSERT_TRUE(cricket::WriteJingleViewRequest( - "video1", view_request, &actual_view_elems, &error)); - - ASSERT_EQ(1U, actual_view_elems.size()); - EXPECT_EQ(expected_view_elem->Str(), actual_view_elems[0]->Str()); - ClearXmlElements(&actual_view_elems); - - cricket::ParseError parse_error; - EXPECT_TRUE(cricket::IsJingleViewRequest(action_elem.get())); - ASSERT_TRUE(cricket::ParseJingleViewRequest( - action_elem.get(), &view_request, &parse_error)); - EXPECT_EQ(0U, view_request.static_video_views.size()); -} - -// Test serializing/deserializing an a simple vga message. -TEST_F(MediaMessagesTest, ViewVgaToFromXml) { - rtc::scoped_ptr action_elem( - new buzz::XmlElement(QN_JINGLE)); - buzz::XmlElement* expected_view_elem1 = - buzz::XmlElement::ForStr(ViewVideoStaticVgaXml("1234")); - buzz::XmlElement* expected_view_elem2 = - buzz::XmlElement::ForStr(ViewVideoStaticVgaXml("2468")); - action_elem->AddElement(expected_view_elem1); - action_elem->AddElement(expected_view_elem2); - - cricket::ViewRequest view_request; - cricket::XmlElements actual_view_elems; - cricket::WriteError error; - - view_request.static_video_views.push_back(cricket::StaticVideoView( - cricket::StreamSelector(1234), 640, 480, 30)); - view_request.static_video_views.push_back(cricket::StaticVideoView( - cricket::StreamSelector(2468), 640, 480, 30)); - - ASSERT_TRUE(cricket::WriteJingleViewRequest( - "video1", view_request, &actual_view_elems, &error)); - - ASSERT_EQ(2U, actual_view_elems.size()); - EXPECT_EQ(expected_view_elem1->Str(), actual_view_elems[0]->Str()); - EXPECT_EQ(expected_view_elem2->Str(), actual_view_elems[1]->Str()); - ClearXmlElements(&actual_view_elems); - - view_request.static_video_views.clear(); - cricket::ParseError parse_error; - EXPECT_TRUE(cricket::IsJingleViewRequest(action_elem.get())); - ASSERT_TRUE(cricket::ParseJingleViewRequest( - action_elem.get(), &view_request, &parse_error)); - EXPECT_EQ(2U, view_request.static_video_views.size()); - EXPECT_EQ(1234U, view_request.static_video_views[0].selector.ssrc); - EXPECT_EQ(640, view_request.static_video_views[0].width); - EXPECT_EQ(480, view_request.static_video_views[0].height); - EXPECT_EQ(30, view_request.static_video_views[0].framerate); - EXPECT_EQ(2468U, view_request.static_video_views[1].selector.ssrc); -} - -// Test deserializing bad view XML. -TEST_F(MediaMessagesTest, ParseBadViewXml) { - rtc::scoped_ptr action_elem( - new buzz::XmlElement(QN_JINGLE)); - buzz::XmlElement* view_elem = - buzz::XmlElement::ForStr(ViewVideoStaticVgaXml("not-an-ssrc")); - action_elem->AddElement(view_elem); - - cricket::ViewRequest view_request; - cricket::ParseError parse_error; - ASSERT_FALSE(cricket::ParseJingleViewRequest( - action_elem.get(), &view_request, &parse_error)); -} - - -// Test serializing/deserializing typical streams xml. -TEST_F(MediaMessagesTest, StreamsToFromXml) { - rtc::scoped_ptr expected_streams_elem( - buzz::XmlElement::ForStr( - StreamsXml( - StreamXml("nick1", "stream1", "101", "102", - "semantics1", "type1", "display1"), - StreamXml("nick2", "stream2", "201", "202", - "semantics2", "type2", "display2")))); - - std::vector expected_streams; - expected_streams.push_back(CreateStream("nick1", "stream1", 101U, 102U, - "semantics1", "type1", "display1")); - expected_streams.push_back(CreateStream("nick2", "stream2", 201U, 202U, - "semantics2", "type2", "display2")); - - rtc::scoped_ptr actual_desc_elem( - new buzz::XmlElement(QN_JINGLE_RTP_CONTENT)); - cricket::WriteJingleStreams(expected_streams, actual_desc_elem.get()); - - const buzz::XmlElement* actual_streams_elem = - actual_desc_elem->FirstNamed(QN_JINGLE_DRAFT_STREAMS); - ASSERT_TRUE(actual_streams_elem != NULL); - EXPECT_EQ(expected_streams_elem->Str(), actual_streams_elem->Str()); - - rtc::scoped_ptr expected_desc_elem( - new buzz::XmlElement(QN_JINGLE_RTP_CONTENT)); - expected_desc_elem->AddElement(new buzz::XmlElement( - *expected_streams_elem)); - std::vector actual_streams; - cricket::ParseError parse_error; - - EXPECT_TRUE(cricket::HasJingleStreams(expected_desc_elem.get())); - ASSERT_TRUE(cricket::ParseJingleStreams( - expected_desc_elem.get(), &actual_streams, &parse_error)); - EXPECT_EQ(2U, actual_streams.size()); - EXPECT_EQ(expected_streams[0], actual_streams[0]); - EXPECT_EQ(expected_streams[1], actual_streams[1]); -} - -// Test deserializing bad streams xml. -TEST_F(MediaMessagesTest, StreamsFromBadXml) { - rtc::scoped_ptr streams_elem( - buzz::XmlElement::ForStr( - StreamsXml( - StreamXml("nick1", "name1", "101", "not-an-ssrc", - "semantics1", "type1", "display1"), - StreamXml("nick2", "name2", "202", "not-an-ssrc", - "semantics2", "type2", "display2")))); - rtc::scoped_ptr desc_elem( - new buzz::XmlElement(QN_JINGLE_RTP_CONTENT)); - desc_elem->AddElement(new buzz::XmlElement(*streams_elem)); - - std::vector actual_streams; - cricket::ParseError parse_error; - ASSERT_FALSE(cricket::ParseJingleStreams( - desc_elem.get(), &actual_streams, &parse_error)); -} - -// Test serializing/deserializing typical RTP Header Extension xml. -TEST_F(MediaMessagesTest, HeaderExtensionsToFromXml) { - rtc::scoped_ptr expected_desc_elem( - buzz::XmlElement::ForStr( - HeaderExtensionsXml( - HeaderExtensionXml("abc", "123"), - HeaderExtensionXml("def", "456")))); - - std::vector expected_hdrexts; - expected_hdrexts.push_back(RtpHeaderExtension("abc", 123)); - expected_hdrexts.push_back(RtpHeaderExtension("def", 456)); - - rtc::scoped_ptr actual_desc_elem( - new buzz::XmlElement(QN_JINGLE_RTP_CONTENT)); - cricket::WriteJingleRtpHeaderExtensions(expected_hdrexts, actual_desc_elem.get()); - - ASSERT_TRUE(actual_desc_elem != NULL); - EXPECT_EQ(expected_desc_elem->Str(), actual_desc_elem->Str()); - - std::vector actual_hdrexts; - cricket::ParseError parse_error; - ASSERT_TRUE(cricket::ParseJingleRtpHeaderExtensions( - expected_desc_elem.get(), &actual_hdrexts, &parse_error)); - EXPECT_EQ(2U, actual_hdrexts.size()); - EXPECT_EQ(expected_hdrexts[0], actual_hdrexts[0]); - EXPECT_EQ(expected_hdrexts[1], actual_hdrexts[1]); -} - -// Test deserializing bad RTP header extension xml. -TEST_F(MediaMessagesTest, HeaderExtensionsFromBadXml) { - std::vector actual_hdrexts; - cricket::ParseError parse_error; - - rtc::scoped_ptr desc_elem( - buzz::XmlElement::ForStr( - HeaderExtensionsXml( - HeaderExtensionXml("abc", "123"), - HeaderExtensionXml("def", "not-an-id")))); - ASSERT_FALSE(cricket::ParseJingleRtpHeaderExtensions( - desc_elem.get(), &actual_hdrexts, &parse_error)); - - desc_elem.reset( - buzz::XmlElement::ForStr( - HeaderExtensionsXml( - HeaderExtensionXml("abc", "123"), - HeaderExtensionXml("def", "-1")))); - ASSERT_FALSE(cricket::ParseJingleRtpHeaderExtensions( - desc_elem.get(), &actual_hdrexts, &parse_error)); -} - -} // namespace cricket diff --git a/webrtc/libjingle/session/media/mediasessionclient.cc b/webrtc/libjingle/session/media/mediasessionclient.cc deleted file mode 100644 index 7cfcf155c..000000000 --- a/webrtc/libjingle/session/media/mediasessionclient.cc +++ /dev/null @@ -1,1160 +0,0 @@ -/* - * 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. - */ - -#include - -#include "webrtc/libjingle/session/media/mediasessionclient.h" - -#include "talk/media/base/capturemanager.h" -#include "talk/media/base/cryptoparams.h" -#include "talk/media/sctp/sctpdataengine.h" -#include "talk/session/media/srtpfilter.h" -#include "webrtc/base/helpers.h" -#include "webrtc/base/logging.h" -#include "webrtc/base/stringencode.h" -#include "webrtc/base/stringutils.h" -#include "webrtc/libjingle/session/media/mediamessages.h" -#include "webrtc/libjingle/xmllite/qname.h" -#include "webrtc/libjingle/xmllite/xmlconstants.h" -#include "webrtc/libjingle/xmpp/constants.h" -#include "webrtc/p2p/base/constants.h" - -namespace cricket { - -#if !defined(DISABLE_MEDIA_ENGINE_FACTORY) -MediaSessionClient::MediaSessionClient( - const buzz::Jid& jid, SessionManager *manager) - : jid_(jid), - session_manager_(manager), - focus_call_(NULL), - channel_manager_(new ChannelManager(session_manager_->worker_thread())), - desc_factory_(channel_manager_, - session_manager_->transport_desc_factory()), - multisession_enabled_(false) { - Construct(); -} -#endif - -MediaSessionClient::MediaSessionClient( - const buzz::Jid& jid, SessionManager *manager, - MediaEngineInterface* media_engine, - DataEngineInterface* data_media_engine, - DeviceManagerInterface* device_manager) - : jid_(jid), - session_manager_(manager), - focus_call_(NULL), - channel_manager_(new ChannelManager( - media_engine, data_media_engine, - device_manager, new CaptureManager(), - session_manager_->worker_thread())), - desc_factory_(channel_manager_, - session_manager_->transport_desc_factory()), - multisession_enabled_(false) { - Construct(); -} - -void MediaSessionClient::Construct() { - // Register ourselves as the handler of audio and video sessions. - session_manager_->AddClient(NS_JINGLE_RTP, this); - // Forward device notifications. - SignalDevicesChange.repeat(channel_manager_->SignalDevicesChange); - // Bring up the channel manager. - // In previous versions of ChannelManager, this was done automatically - // in the constructor. - channel_manager_->Init(); -} - -MediaSessionClient::~MediaSessionClient() { - // Destroy all calls - std::map::iterator it; - while (calls_.begin() != calls_.end()) { - std::map::iterator it = calls_.begin(); - DestroyCall((*it).second); - } - - // Delete channel manager. This will wait for the channels to exit - delete channel_manager_; - - // Remove ourselves from the client map. - session_manager_->RemoveClient(NS_JINGLE_RTP); -} - -Call *MediaSessionClient::CreateCall() { - Call *call = new Call(this); - calls_[call->id()] = call; - SignalCallCreate(call); - return call; -} - -void MediaSessionClient::OnSessionCreate(Session *session, - bool received_initiate) { - if (received_initiate) { - session->SignalState.connect(this, &MediaSessionClient::OnSessionState); - } -} - -void MediaSessionClient::OnSessionState(BaseSession* base_session, - BaseSession::State state) { - // MediaSessionClient can only be used with a Session*, so it's - // safe to cast here. - Session* session = static_cast(base_session); - - if (state == Session::STATE_RECEIVEDINITIATE) { - // The creation of the call must happen after the session has - // processed the initiate message because we need the - // remote_description to know what content names to use in the - // call. - - // If our accept would have no codecs, then we must reject this call. - const SessionDescription* offer = session->remote_description(); - const SessionDescription* accept = CreateAnswer(offer, CallOptions()); - const ContentInfo* audio_content = GetFirstAudioContent(accept); - bool audio_rejected = (!audio_content) ? true : audio_content->rejected; - const AudioContentDescription* audio_desc = (!audio_content) ? NULL : - static_cast(audio_content->description); - - // For some reason, we need a call even if we reject. So, either find a - // matching call or create a new one. - // The matching of existing calls is used to support the multi-session mode - // required for p2p handoffs: ie. once a MUC call is established, a new - // session may be established for the same call but is direct between the - // clients. To indicate that this is the case, the initiator of the incoming - // session is set to be the same as the remote name of the MUC for the - // existing session, thus the client can know that this is a new session for - // the existing call, rather than a whole new call. - Call* call = NULL; - if (multisession_enabled_) { - call = FindCallByRemoteName(session->initiator_name()); - } - - if (call == NULL) { - // Could not find a matching call, so create a new one. - call = CreateCall(); - } - - session_map_[session->id()] = call; - call->IncomingSession(session, offer); - - if (audio_rejected || !audio_desc || audio_desc->codecs().size() == 0) { - session->Reject(STR_TERMINATE_INCOMPATIBLE_PARAMETERS); - } - delete accept; - } -} - -void MediaSessionClient::DestroyCall(Call *call) { - // Change focus away, signal destruction - - if (call == focus_call_) - SetFocus(NULL); - SignalCallDestroy(call); - - // Remove it from calls_ map and delete - - std::map::iterator it = calls_.find(call->id()); - if (it != calls_.end()) - calls_.erase(it); - - delete call; -} - -void MediaSessionClient::OnSessionDestroy(Session *session) { - // Find the call this session is in, remove it - SessionMap::iterator it = session_map_.find(session->id()); - ASSERT(it != session_map_.end()); - if (it != session_map_.end()) { - Call *call = (*it).second; - session_map_.erase(it); - call->RemoveSession(session); - } -} - -Call *MediaSessionClient::GetFocus() { - return focus_call_; -} - -void MediaSessionClient::SetFocus(Call *call) { - Call *old_focus_call = focus_call_; - if (focus_call_ != call) { - if (focus_call_ != NULL) - focus_call_->EnableChannels(false); - focus_call_ = call; - if (focus_call_ != NULL) - focus_call_->EnableChannels(true); - SignalFocus(focus_call_, old_focus_call); - } -} - -void MediaSessionClient::JoinCalls(Call *call_to_join, Call *call) { - // Move all sessions from call to call_to_join, delete call. - // If call_to_join has focus, added sessions should have enabled channels. - - if (focus_call_ == call) - SetFocus(NULL); - call_to_join->Join(call, focus_call_ == call_to_join); - DestroyCall(call); -} - -Session *MediaSessionClient::CreateSession(Call *call) { - std::string id; - return CreateSession(id, call); -} - -Session *MediaSessionClient::CreateSession(const std::string& id, Call* call) { - const std::string& type = NS_JINGLE_RTP; - Session *session = session_manager_->CreateSession(id, jid().Str(), type); - session_map_[session->id()] = call; - return session; -} - -Call *MediaSessionClient::FindCallByRemoteName(const std::string &remote_name) { - SessionMap::const_iterator call; - for (call = session_map_.begin(); call != session_map_.end(); ++call) { - std::vector sessions = call->second->sessions(); - std::vector::const_iterator session; - for (session = sessions.begin(); session != sessions.end(); ++session) { - if (remote_name == (*session)->remote_name()) { - return call->second; - } - } - } - - return NULL; -} - -// TODO(pthatcher): Move all of the parsing and writing functions into -// mediamessages.cc, with unit tests. -bool ParseGingleAudioCodec(const buzz::XmlElement* element, AudioCodec* out) { - int id = GetXmlAttr(element, QN_ID, -1); - if (id < 0) - return false; - - std::string name = GetXmlAttr(element, QN_NAME, buzz::STR_EMPTY); - int clockrate = GetXmlAttr(element, QN_CLOCKRATE, 0); - int bitrate = GetXmlAttr(element, QN_BITRATE, 0); - int channels = GetXmlAttr(element, QN_CHANNELS, 1); - *out = AudioCodec(id, name, clockrate, bitrate, channels, 0); - return true; -} - -bool ParseGingleVideoCodec(const buzz::XmlElement* element, VideoCodec* out) { - int id = GetXmlAttr(element, QN_ID, -1); - if (id < 0) - return false; - - std::string name = GetXmlAttr(element, QN_NAME, buzz::STR_EMPTY); - int width = GetXmlAttr(element, QN_WIDTH, 0); - int height = GetXmlAttr(element, QN_HEIGHT, 0); - int framerate = GetXmlAttr(element, QN_FRAMERATE, 0); - - *out = VideoCodec(id, name, width, height, framerate, 0); - return true; -} - -// Parses an ssrc string as a legacy stream. If it fails, returns -// false and fills an error message. -bool ParseSsrcAsLegacyStream(const std::string& ssrc_str, - std::vector* streams, - ParseError* error) { - if (!ssrc_str.empty()) { - uint32 ssrc; - if (!rtc::FromString(ssrc_str, &ssrc)) { - return BadParse("Missing or invalid ssrc.", error); - } - - streams->push_back(StreamParams::CreateLegacy(ssrc)); - } - return true; -} - -void ParseGingleSsrc(const buzz::XmlElement* parent_elem, - const buzz::QName& name, - MediaContentDescription* media) { - const buzz::XmlElement* ssrc_elem = parent_elem->FirstNamed(name); - if (ssrc_elem) { - ParseError error; - ParseSsrcAsLegacyStream( - ssrc_elem->BodyText(), &(media->mutable_streams()), &error); - } -} - -bool ParseCryptoParams(const buzz::XmlElement* element, - CryptoParams* out, - ParseError* error) { - if (!element->HasAttr(QN_CRYPTO_SUITE)) { - return BadParse("crypto: crypto-suite attribute missing ", error); - } else if (!element->HasAttr(QN_CRYPTO_KEY_PARAMS)) { - return BadParse("crypto: key-params attribute missing ", error); - } else if (!element->HasAttr(QN_CRYPTO_TAG)) { - return BadParse("crypto: tag attribute missing ", error); - } - - const std::string& crypto_suite = element->Attr(QN_CRYPTO_SUITE); - const std::string& key_params = element->Attr(QN_CRYPTO_KEY_PARAMS); - const int tag = GetXmlAttr(element, QN_CRYPTO_TAG, 0); - const std::string& session_params = - element->Attr(QN_CRYPTO_SESSION_PARAMS); // Optional. - - *out = CryptoParams(tag, crypto_suite, key_params, session_params); - return true; -} - - -// Parse the first encryption element found with a matching 'usage' -// element. -// is specific to Gingle. In Jingle, is already -// scoped to a content. -// Return false if there was an encryption element and it could not be -// parsed. -bool ParseGingleEncryption(const buzz::XmlElement* desc, - const buzz::QName& usage, - MediaContentDescription* media, - ParseError* error) { - for (const buzz::XmlElement* encryption = desc->FirstNamed(QN_ENCRYPTION); - encryption != NULL; - encryption = encryption->NextNamed(QN_ENCRYPTION)) { - if (encryption->FirstNamed(usage) != NULL) { - if (GetXmlAttr(encryption, QN_ENCRYPTION_REQUIRED, false)) { - media->set_crypto_required(CT_SDES); - } - for (const buzz::XmlElement* crypto = encryption->FirstNamed(QN_CRYPTO); - crypto != NULL; - crypto = crypto->NextNamed(QN_CRYPTO)) { - CryptoParams params; - if (!ParseCryptoParams(crypto, ¶ms, error)) { - return false; - } - media->AddCrypto(params); - } - break; - } - } - return true; -} - -void ParseBandwidth(const buzz::XmlElement* parent_elem, - MediaContentDescription* media) { - const buzz::XmlElement* bw_elem = GetXmlChild(parent_elem, LN_BANDWIDTH); - int bandwidth_kbps = -1; - if (bw_elem && rtc::FromString(bw_elem->BodyText(), &bandwidth_kbps)) { - if (bandwidth_kbps >= 0) { - media->set_bandwidth(bandwidth_kbps * 1000); - } - } -} - -bool ParseGingleAudioContent(const buzz::XmlElement* content_elem, - ContentDescription** content, - ParseError* error) { - AudioContentDescription* audio = new AudioContentDescription(); - - int preference = kMaxPayloadId; - if (content_elem->FirstElement()) { - for (const buzz::XmlElement* codec_elem = - content_elem->FirstNamed(QN_GINGLE_AUDIO_PAYLOADTYPE); - codec_elem != NULL; - codec_elem = codec_elem->NextNamed(QN_GINGLE_AUDIO_PAYLOADTYPE)) { - AudioCodec codec; - if (ParseGingleAudioCodec(codec_elem, &codec)) { - codec.preference = preference--; - audio->AddCodec(codec); - } - } - } else { - // For backward compatibility, we can assume the other client is - // an old version of Talk if it has no audio payload types at all. - audio->AddCodec(AudioCodec(103, "ISAC", 16000, -1, 1, 1)); - audio->AddCodec(AudioCodec(0, "PCMU", 8000, 64000, 1, 0)); - } - - ParseGingleSsrc(content_elem, QN_GINGLE_AUDIO_SRCID, audio); - - if (!ParseGingleEncryption(content_elem, QN_GINGLE_AUDIO_CRYPTO_USAGE, - audio, error)) { - return false; - } - - *content = audio; - return true; -} - -bool ParseGingleVideoContent(const buzz::XmlElement* content_elem, - ContentDescription** content, - ParseError* error) { - VideoContentDescription* video = new VideoContentDescription(); - - int preference = kMaxPayloadId; - for (const buzz::XmlElement* codec_elem = - content_elem->FirstNamed(QN_GINGLE_VIDEO_PAYLOADTYPE); - codec_elem != NULL; - codec_elem = codec_elem->NextNamed(QN_GINGLE_VIDEO_PAYLOADTYPE)) { - VideoCodec codec; - if (ParseGingleVideoCodec(codec_elem, &codec)) { - codec.preference = preference--; - video->AddCodec(codec); - } - } - - ParseGingleSsrc(content_elem, QN_GINGLE_VIDEO_SRCID, video); - ParseBandwidth(content_elem, video); - - if (!ParseGingleEncryption(content_elem, QN_GINGLE_VIDEO_CRYPTO_USAGE, - video, error)) { - return false; - } - - *content = video; - return true; -} - -void ParsePayloadTypeParameters(const buzz::XmlElement* element, - std::map* paramap) { - for (const buzz::XmlElement* param = element->FirstNamed(QN_PARAMETER); - param != NULL; param = param->NextNamed(QN_PARAMETER)) { - std::string name = GetXmlAttr(param, QN_PAYLOADTYPE_PARAMETER_NAME, - buzz::STR_EMPTY); - std::string value = GetXmlAttr(param, QN_PAYLOADTYPE_PARAMETER_VALUE, - buzz::STR_EMPTY); - if (!name.empty() && !value.empty()) { - paramap->insert(make_pair(name, value)); - } - } -} - -void ParseFeedbackParams(const buzz::XmlElement* element, - FeedbackParams* params) { - for (const buzz::XmlElement* param = element->FirstNamed(QN_JINGLE_RTCP_FB); - param != NULL; param = param->NextNamed(QN_JINGLE_RTCP_FB)) { - std::string type = GetXmlAttr(param, QN_TYPE, buzz::STR_EMPTY); - std::string subtype = GetXmlAttr(param, QN_SUBTYPE, buzz::STR_EMPTY); - if (!type.empty()) { - params->Add(FeedbackParam(type, subtype)); - } - } -} - -void AddFeedbackParams(const FeedbackParams& additional_params, - FeedbackParams* params) { - for (size_t i = 0; i < additional_params.params().size(); ++i) { - params->Add(additional_params.params()[i]); - } -} - -int FindWithDefault(const std::map& map, - const std::string& key, const int def) { - std::map::const_iterator iter = map.find(key); - return (iter == map.end()) ? def : atoi(iter->second.c_str()); -} - - -// Parse the first encryption element found. -// Return false if there was an encryption element and it could not be -// parsed. -bool ParseJingleEncryption(const buzz::XmlElement* content_elem, - MediaContentDescription* media, - ParseError* error) { - const buzz::XmlElement* encryption = - content_elem->FirstNamed(QN_ENCRYPTION); - if (encryption == NULL) { - return true; - } - - if (GetXmlAttr(encryption, QN_ENCRYPTION_REQUIRED, false)) { - media->set_crypto_required(CT_SDES); - } - - for (const buzz::XmlElement* crypto = encryption->FirstNamed(QN_CRYPTO); - crypto != NULL; - crypto = crypto->NextNamed(QN_CRYPTO)) { - CryptoParams params; - if (!ParseCryptoParams(crypto, ¶ms, error)) { - return false; - } - media->AddCrypto(params); - } - return true; -} - -bool ParseJingleAudioCodec(const buzz::XmlElement* elem, AudioCodec* codec) { - int id = GetXmlAttr(elem, QN_ID, -1); - if (id < 0) - return false; - - std::string name = GetXmlAttr(elem, QN_NAME, buzz::STR_EMPTY); - int clockrate = GetXmlAttr(elem, QN_CLOCKRATE, 0); - int channels = GetXmlAttr(elem, QN_CHANNELS, 1); - - std::map paramap; - ParsePayloadTypeParameters(elem, ¶map); - int bitrate = FindWithDefault(paramap, PAYLOADTYPE_PARAMETER_BITRATE, 0); - - *codec = AudioCodec(id, name, clockrate, bitrate, channels, 0); - ParseFeedbackParams(elem, &codec->feedback_params); - return true; -} - -bool ParseJingleVideoCodec(const buzz::XmlElement* elem, VideoCodec* codec) { - int id = GetXmlAttr(elem, QN_ID, -1); - if (id < 0) - return false; - - std::string name = GetXmlAttr(elem, QN_NAME, buzz::STR_EMPTY); - - std::map paramap; - ParsePayloadTypeParameters(elem, ¶map); - int width = FindWithDefault(paramap, PAYLOADTYPE_PARAMETER_WIDTH, 0); - int height = FindWithDefault(paramap, PAYLOADTYPE_PARAMETER_HEIGHT, 0); - int framerate = FindWithDefault(paramap, PAYLOADTYPE_PARAMETER_FRAMERATE, 0); - - *codec = VideoCodec(id, name, width, height, framerate, 0); - codec->params = paramap; - ParseFeedbackParams(elem, &codec->feedback_params); - return true; -} - -bool ParseJingleDataCodec(const buzz::XmlElement* elem, DataCodec* codec) { - int id = GetXmlAttr(elem, QN_ID, -1); - if (id < 0) - return false; - - std::string name = GetXmlAttr(elem, QN_NAME, buzz::STR_EMPTY); - - *codec = DataCodec(id, name, 0); - ParseFeedbackParams(elem, &codec->feedback_params); - return true; -} - -bool ParseJingleStreamsOrLegacySsrc(const buzz::XmlElement* desc_elem, - MediaContentDescription* media, - ParseError* error) { - if (HasJingleStreams(desc_elem)) { - if (!ParseJingleStreams(desc_elem, &(media->mutable_streams()), error)) { - return false; - } - } else { - const std::string ssrc_str = desc_elem->Attr(QN_SSRC); - if (!ParseSsrcAsLegacyStream( - ssrc_str, &(media->mutable_streams()), error)) { - return false; - } - } - return true; -} - -bool ParseJingleAudioContent(const buzz::XmlElement* content_elem, - ContentDescription** content, - ParseError* error) { - rtc::scoped_ptr audio( - new AudioContentDescription()); - - FeedbackParams content_feedback_params; - ParseFeedbackParams(content_elem, &content_feedback_params); - - int preference = kMaxPayloadId; - for (const buzz::XmlElement* payload_elem = - content_elem->FirstNamed(QN_JINGLE_RTP_PAYLOADTYPE); - payload_elem != NULL; - payload_elem = payload_elem->NextNamed(QN_JINGLE_RTP_PAYLOADTYPE)) { - AudioCodec codec; - if (ParseJingleAudioCodec(payload_elem, &codec)) { - AddFeedbackParams(content_feedback_params, &codec.feedback_params); - codec.preference = preference--; - audio->AddCodec(codec); - } - } - - if (!ParseJingleStreamsOrLegacySsrc(content_elem, audio.get(), error)) { - return false; - } - - if (!ParseJingleEncryption(content_elem, audio.get(), error)) { - return false; - } - - audio->set_rtcp_mux(content_elem->FirstNamed(QN_JINGLE_RTCP_MUX) != NULL); - - RtpHeaderExtensions hdrexts; - if (!ParseJingleRtpHeaderExtensions(content_elem, &hdrexts, error)) { - return false; - } - audio->set_rtp_header_extensions(hdrexts); - - *content = audio.release(); - return true; -} - -bool ParseJingleVideoContent(const buzz::XmlElement* content_elem, - ContentDescription** content, - ParseError* error) { - rtc::scoped_ptr video( - new VideoContentDescription()); - - FeedbackParams content_feedback_params; - ParseFeedbackParams(content_elem, &content_feedback_params); - - int preference = kMaxPayloadId; - for (const buzz::XmlElement* payload_elem = - content_elem->FirstNamed(QN_JINGLE_RTP_PAYLOADTYPE); - payload_elem != NULL; - payload_elem = payload_elem->NextNamed(QN_JINGLE_RTP_PAYLOADTYPE)) { - VideoCodec codec; - if (ParseJingleVideoCodec(payload_elem, &codec)) { - AddFeedbackParams(content_feedback_params, &codec.feedback_params); - codec.preference = preference--; - video->AddCodec(codec); - } - } - - if (!ParseJingleStreamsOrLegacySsrc(content_elem, video.get(), error)) { - return false; - } - ParseBandwidth(content_elem, video.get()); - - if (!ParseJingleEncryption(content_elem, video.get(), error)) { - return false; - } - - video->set_rtcp_mux(content_elem->FirstNamed(QN_JINGLE_RTCP_MUX) != NULL); - - RtpHeaderExtensions hdrexts; - if (!ParseJingleRtpHeaderExtensions(content_elem, &hdrexts, error)) { - return false; - } - video->set_rtp_header_extensions(hdrexts); - - *content = video.release(); - return true; -} - -bool ParseJingleSctpDataContent(const buzz::XmlElement* content_elem, - ContentDescription** content, - ParseError* error) { - rtc::scoped_ptr data( - new DataContentDescription()); - data->set_protocol(kMediaProtocolSctp); - - for (const buzz::XmlElement* stream_elem = - content_elem->FirstNamed(QN_JINGLE_DRAFT_SCTP_STREAM); - stream_elem != NULL; - stream_elem = stream_elem->NextNamed(QN_JINGLE_DRAFT_SCTP_STREAM)) { - StreamParams stream; - stream.groupid = stream_elem->Attr(QN_NICK); - stream.id = stream_elem->Attr(QN_NAME); - uint32 sid; - if (!rtc::FromString(stream_elem->Attr(QN_SID), &sid)) { - return BadParse("Missing or invalid sid.", error); - } - if (sid > kMaxSctpSid) { - return BadParse("SID is greater than max value.", error); - } - - stream.ssrcs.push_back(sid); - data->mutable_streams().push_back(stream); - } - - *content = data.release(); - return true; -} - -bool ParseJingleRtpDataContent(const buzz::XmlElement* content_elem, - ContentDescription** content, - ParseError* error) { - DataContentDescription* data = new DataContentDescription(); - - FeedbackParams content_feedback_params; - ParseFeedbackParams(content_elem, &content_feedback_params); - - int preference = kMaxPayloadId; - for (const buzz::XmlElement* payload_elem = - content_elem->FirstNamed(QN_JINGLE_RTP_PAYLOADTYPE); - payload_elem != NULL; - payload_elem = payload_elem->NextNamed(QN_JINGLE_RTP_PAYLOADTYPE)) { - DataCodec codec; - if (ParseJingleDataCodec(payload_elem, &codec)) { - AddFeedbackParams(content_feedback_params, &codec.feedback_params); - codec.preference = preference--; - data->AddCodec(codec); - } - } - - if (!ParseJingleStreamsOrLegacySsrc(content_elem, data, error)) { - return false; - } - ParseBandwidth(content_elem, data); - - if (!ParseJingleEncryption(content_elem, data, error)) { - return false; - } - - data->set_rtcp_mux(content_elem->FirstNamed(QN_JINGLE_RTCP_MUX) != NULL); - - *content = data; - return true; -} - -bool MediaSessionClient::ParseContent(SignalingProtocol protocol, - const buzz::XmlElement* content_elem, - ContentDescription** content, - ParseError* error) { - if (protocol == PROTOCOL_GINGLE) { - const std::string& content_type = content_elem->Name().Namespace(); - if (NS_GINGLE_AUDIO == content_type) { - return ParseGingleAudioContent(content_elem, content, error); - } else if (NS_GINGLE_VIDEO == content_type) { - return ParseGingleVideoContent(content_elem, content, error); - } else { - return BadParse("Unknown content type: " + content_type, error); - } - } else { - const std::string& content_type = content_elem->Name().Namespace(); - // We use the XMLNS of the element to determine if - // it's RTP or SCTP. - if (content_type == NS_JINGLE_DRAFT_SCTP) { - return ParseJingleSctpDataContent(content_elem, content, error); - } - - std::string media; - if (!RequireXmlAttr(content_elem, QN_JINGLE_CONTENT_MEDIA, &media, error)) - return false; - - if (media == JINGLE_CONTENT_MEDIA_AUDIO) { - return ParseJingleAudioContent(content_elem, content, error); - } else if (media == JINGLE_CONTENT_MEDIA_VIDEO) { - return ParseJingleVideoContent(content_elem, content, error); - } else if (media == JINGLE_CONTENT_MEDIA_DATA) { - return ParseJingleRtpDataContent(content_elem, content, error); - } else { - return BadParse("Unknown media: " + media, error); - } - } -} - -buzz::XmlElement* CreateGingleAudioCodecElem(const AudioCodec& codec) { - buzz::XmlElement* payload_type = - new buzz::XmlElement(QN_GINGLE_AUDIO_PAYLOADTYPE, true); - AddXmlAttr(payload_type, QN_ID, codec.id); - payload_type->AddAttr(QN_NAME, codec.name); - if (codec.clockrate > 0) - AddXmlAttr(payload_type, QN_CLOCKRATE, codec.clockrate); - if (codec.bitrate > 0) - AddXmlAttr(payload_type, QN_BITRATE, codec.bitrate); - if (codec.channels > 1) - AddXmlAttr(payload_type, QN_CHANNELS, codec.channels); - return payload_type; -} - -buzz::XmlElement* CreateGingleVideoCodecElem(const VideoCodec& codec) { - buzz::XmlElement* payload_type = - new buzz::XmlElement(QN_GINGLE_VIDEO_PAYLOADTYPE, true); - AddXmlAttr(payload_type, QN_ID, codec.id); - payload_type->AddAttr(QN_NAME, codec.name); - AddXmlAttr(payload_type, QN_WIDTH, codec.width); - AddXmlAttr(payload_type, QN_HEIGHT, codec.height); - AddXmlAttr(payload_type, QN_FRAMERATE, codec.framerate); - return payload_type; -} - -buzz::XmlElement* CreateGingleSsrcElem(const buzz::QName& name, uint32 ssrc) { - buzz::XmlElement* elem = new buzz::XmlElement(name, true); - if (ssrc) { - SetXmlBody(elem, ssrc); - } - return elem; -} - -buzz::XmlElement* CreateBandwidthElem(const buzz::QName& name, int bps) { - int kbps = bps / 1000; - buzz::XmlElement* elem = new buzz::XmlElement(name); - elem->AddAttr(buzz::QN_TYPE, "AS"); - SetXmlBody(elem, kbps); - return elem; -} - -// For Jingle, usage_qname is empty. -buzz::XmlElement* CreateJingleEncryptionElem(const CryptoParamsVec& cryptos, - bool required) { - buzz::XmlElement* encryption_elem = new buzz::XmlElement(QN_ENCRYPTION); - - if (required) { - encryption_elem->SetAttr(QN_ENCRYPTION_REQUIRED, "true"); - } - - for (CryptoParamsVec::const_iterator i = cryptos.begin(); - i != cryptos.end(); - ++i) { - buzz::XmlElement* crypto_elem = new buzz::XmlElement(QN_CRYPTO); - - AddXmlAttr(crypto_elem, QN_CRYPTO_TAG, i->tag); - crypto_elem->AddAttr(QN_CRYPTO_SUITE, i->cipher_suite); - crypto_elem->AddAttr(QN_CRYPTO_KEY_PARAMS, i->key_params); - if (!i->session_params.empty()) { - crypto_elem->AddAttr(QN_CRYPTO_SESSION_PARAMS, i->session_params); - } - encryption_elem->AddElement(crypto_elem); - } - return encryption_elem; -} - -buzz::XmlElement* CreateGingleEncryptionElem(const CryptoParamsVec& cryptos, - const buzz::QName& usage_qname, - bool required) { - buzz::XmlElement* encryption_elem = - CreateJingleEncryptionElem(cryptos, required); - - if (required) { - encryption_elem->SetAttr(QN_ENCRYPTION_REQUIRED, "true"); - } - - buzz::XmlElement* usage_elem = new buzz::XmlElement(usage_qname); - encryption_elem->AddElement(usage_elem); - - return encryption_elem; -} - -buzz::XmlElement* CreateGingleAudioContentElem( - const AudioContentDescription* audio, - bool crypto_required) { - buzz::XmlElement* elem = - new buzz::XmlElement(QN_GINGLE_AUDIO_CONTENT, true); - - for (AudioCodecs::const_iterator codec = audio->codecs().begin(); - codec != audio->codecs().end(); ++codec) { - elem->AddElement(CreateGingleAudioCodecElem(*codec)); - } - if (audio->has_ssrcs()) { - elem->AddElement(CreateGingleSsrcElem( - QN_GINGLE_AUDIO_SRCID, audio->first_ssrc())); - } - - const CryptoParamsVec& cryptos = audio->cryptos(); - if (!cryptos.empty()) { - elem->AddElement(CreateGingleEncryptionElem(cryptos, - QN_GINGLE_AUDIO_CRYPTO_USAGE, - crypto_required)); - } - return elem; -} - -buzz::XmlElement* CreateGingleVideoContentElem( - const VideoContentDescription* video, - bool crypto_required) { - buzz::XmlElement* elem = - new buzz::XmlElement(QN_GINGLE_VIDEO_CONTENT, true); - - for (VideoCodecs::const_iterator codec = video->codecs().begin(); - codec != video->codecs().end(); ++codec) { - elem->AddElement(CreateGingleVideoCodecElem(*codec)); - } - if (video->has_ssrcs()) { - elem->AddElement(CreateGingleSsrcElem( - QN_GINGLE_VIDEO_SRCID, video->first_ssrc())); - } - if (video->bandwidth() != kAutoBandwidth) { - elem->AddElement(CreateBandwidthElem(QN_GINGLE_VIDEO_BANDWIDTH, - video->bandwidth())); - } - - const CryptoParamsVec& cryptos = video->cryptos(); - if (!cryptos.empty()) { - elem->AddElement(CreateGingleEncryptionElem(cryptos, - QN_GINGLE_VIDEO_CRYPTO_USAGE, - crypto_required)); - } - - return elem; -} - -template -buzz::XmlElement* CreatePayloadTypeParameterElem( - const std::string& name, T value) { - buzz::XmlElement* elem = new buzz::XmlElement(QN_PARAMETER); - - elem->AddAttr(QN_PAYLOADTYPE_PARAMETER_NAME, name); - AddXmlAttr(elem, QN_PAYLOADTYPE_PARAMETER_VALUE, value); - - return elem; -} - -void AddRtcpFeedbackElem(buzz::XmlElement* elem, - const FeedbackParams& feedback_params) { - std::vector::const_iterator it; - for (it = feedback_params.params().begin(); - it != feedback_params.params().end(); ++it) { - buzz::XmlElement* fb_elem = new buzz::XmlElement(QN_JINGLE_RTCP_FB); - fb_elem->AddAttr(QN_TYPE, it->id()); - fb_elem->AddAttr(QN_SUBTYPE, it->param()); - elem->AddElement(fb_elem); - } -} - -buzz::XmlElement* CreateJingleAudioCodecElem(const AudioCodec& codec) { - buzz::XmlElement* elem = new buzz::XmlElement(QN_JINGLE_RTP_PAYLOADTYPE); - - AddXmlAttr(elem, QN_ID, codec.id); - elem->AddAttr(QN_NAME, codec.name); - if (codec.clockrate > 0) { - AddXmlAttr(elem, QN_CLOCKRATE, codec.clockrate); - } - if (codec.bitrate > 0) { - elem->AddElement(CreatePayloadTypeParameterElem( - PAYLOADTYPE_PARAMETER_BITRATE, codec.bitrate)); - } - if (codec.channels > 1) { - AddXmlAttr(elem, QN_CHANNELS, codec.channels); - } - - AddRtcpFeedbackElem(elem, codec.feedback_params); - - return elem; -} - -buzz::XmlElement* CreateJingleVideoCodecElem(const VideoCodec& codec) { - buzz::XmlElement* elem = new buzz::XmlElement(QN_JINGLE_RTP_PAYLOADTYPE); - - AddXmlAttr(elem, QN_ID, codec.id); - elem->AddAttr(QN_NAME, codec.name); - elem->AddElement(CreatePayloadTypeParameterElem( - PAYLOADTYPE_PARAMETER_WIDTH, codec.width)); - elem->AddElement(CreatePayloadTypeParameterElem( - PAYLOADTYPE_PARAMETER_HEIGHT, codec.height)); - elem->AddElement(CreatePayloadTypeParameterElem( - PAYLOADTYPE_PARAMETER_FRAMERATE, codec.framerate)); - - AddRtcpFeedbackElem(elem, codec.feedback_params); - - CodecParameterMap::const_iterator param_iter; - for (param_iter = codec.params.begin(); param_iter != codec.params.end(); - ++param_iter) { - elem->AddElement(CreatePayloadTypeParameterElem(param_iter->first, - param_iter->second)); - } - - return elem; -} - -buzz::XmlElement* CreateJingleDataCodecElem(const DataCodec& codec) { - buzz::XmlElement* elem = new buzz::XmlElement(QN_JINGLE_RTP_PAYLOADTYPE); - - AddXmlAttr(elem, QN_ID, codec.id); - elem->AddAttr(QN_NAME, codec.name); - - AddRtcpFeedbackElem(elem, codec.feedback_params); - - return elem; -} - -void WriteLegacyJingleSsrc(const MediaContentDescription* media, - buzz::XmlElement* elem) { - if (media->has_ssrcs()) { - AddXmlAttr(elem, QN_SSRC, media->first_ssrc()); - } -} - -void WriteJingleStreamsOrLegacySsrc(const MediaContentDescription* media, - buzz::XmlElement* desc_elem) { - if (!media->multistream()) { - WriteLegacyJingleSsrc(media, desc_elem); - } else { - WriteJingleStreams(media->streams(), desc_elem); - } -} - -buzz::XmlElement* CreateJingleAudioContentElem( - const AudioContentDescription* audio, bool crypto_required) { - buzz::XmlElement* elem = - new buzz::XmlElement(QN_JINGLE_RTP_CONTENT, true); - - elem->SetAttr(QN_JINGLE_CONTENT_MEDIA, JINGLE_CONTENT_MEDIA_AUDIO); - WriteJingleStreamsOrLegacySsrc(audio, elem); - - for (AudioCodecs::const_iterator codec = audio->codecs().begin(); - codec != audio->codecs().end(); ++codec) { - elem->AddElement(CreateJingleAudioCodecElem(*codec)); - } - - const CryptoParamsVec& cryptos = audio->cryptos(); - if (!cryptos.empty()) { - elem->AddElement(CreateJingleEncryptionElem(cryptos, crypto_required)); - } - - if (audio->rtcp_mux()) { - elem->AddElement(new buzz::XmlElement(QN_JINGLE_RTCP_MUX)); - } - - WriteJingleRtpHeaderExtensions(audio->rtp_header_extensions(), elem); - - return elem; -} - -buzz::XmlElement* CreateJingleVideoContentElem( - const VideoContentDescription* video, bool crypto_required) { - buzz::XmlElement* elem = - new buzz::XmlElement(QN_JINGLE_RTP_CONTENT, true); - - elem->SetAttr(QN_JINGLE_CONTENT_MEDIA, JINGLE_CONTENT_MEDIA_VIDEO); - WriteJingleStreamsOrLegacySsrc(video, elem); - - for (VideoCodecs::const_iterator codec = video->codecs().begin(); - codec != video->codecs().end(); ++codec) { - elem->AddElement(CreateJingleVideoCodecElem(*codec)); - } - - const CryptoParamsVec& cryptos = video->cryptos(); - if (!cryptos.empty()) { - 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())); - } - - WriteJingleRtpHeaderExtensions(video->rtp_header_extensions(), elem); - - return elem; -} - -buzz::XmlElement* CreateJingleSctpDataContentElem( - const DataContentDescription* data) { - buzz::XmlElement* content_elem = - new buzz::XmlElement(QN_JINGLE_DRAFT_SCTP_CONTENT, true); - for (std::vector::const_iterator - stream = data->streams().begin(); - stream != data->streams().end(); ++stream) { - buzz::XmlElement* stream_elem = - new buzz::XmlElement(QN_JINGLE_DRAFT_SCTP_STREAM, false); - AddXmlAttrIfNonEmpty(stream_elem, QN_NICK, stream->groupid); - AddXmlAttrIfNonEmpty(stream_elem, QN_NAME, stream->id); - if (!stream->ssrcs.empty()) { - AddXmlAttr(stream_elem, QN_SID, stream->ssrcs[0]); - } - content_elem->AddElement(stream_elem); - } - return content_elem;; -} - -buzz::XmlElement* CreateJingleRtpDataContentElem( - const DataContentDescription* data, bool crypto_required) { - - buzz::XmlElement* elem = - new buzz::XmlElement(QN_JINGLE_RTP_CONTENT, true); - - elem->SetAttr(QN_JINGLE_CONTENT_MEDIA, JINGLE_CONTENT_MEDIA_DATA); - WriteJingleStreamsOrLegacySsrc(data, elem); - - for (DataCodecs::const_iterator codec = data->codecs().begin(); - codec != data->codecs().end(); ++codec) { - elem->AddElement(CreateJingleDataCodecElem(*codec)); - } - - const CryptoParamsVec& cryptos = data->cryptos(); - if (!cryptos.empty()) { - elem->AddElement(CreateJingleEncryptionElem(cryptos, crypto_required)); - } - - if (data->rtcp_mux()) { - elem->AddElement(new buzz::XmlElement(QN_JINGLE_RTCP_MUX)); - } - - if (data->bandwidth() != kAutoBandwidth) { - elem->AddElement(CreateBandwidthElem(QN_JINGLE_RTP_BANDWIDTH, - data->bandwidth())); - } - - return elem; -} - -bool IsSctp(const DataContentDescription* data) { - return (data->protocol() == kMediaProtocolSctp || - data->protocol() == kMediaProtocolDtlsSctp); -} - -buzz::XmlElement* CreateJingleDataContentElem( - const DataContentDescription* data, bool crypto_required) { - if (IsSctp(data)) { - return CreateJingleSctpDataContentElem(data); - } else { - return CreateJingleRtpDataContentElem(data, crypto_required); - } -} - -bool MediaSessionClient::IsWritable(SignalingProtocol protocol, - const ContentDescription* content) { - const MediaContentDescription* media = - static_cast(content); - if (protocol == PROTOCOL_GINGLE && - media->type() == MEDIA_TYPE_DATA) { - return false; - } - return true; -} - -bool MediaSessionClient::WriteContent(SignalingProtocol protocol, - const ContentDescription* content, - buzz::XmlElement** elem, - WriteError* error) { - const MediaContentDescription* media = - static_cast(content); - bool crypto_required = secure() == SEC_REQUIRED; - - if (media->type() == MEDIA_TYPE_AUDIO) { - const AudioContentDescription* audio = - static_cast(media); - if (protocol == PROTOCOL_GINGLE) { - *elem = CreateGingleAudioContentElem(audio, crypto_required); - } else { - *elem = CreateJingleAudioContentElem(audio, crypto_required); - } - } else if (media->type() == MEDIA_TYPE_VIDEO) { - const VideoContentDescription* video = - static_cast(media); - if (protocol == PROTOCOL_GINGLE) { - *elem = CreateGingleVideoContentElem(video, crypto_required); - } else { - *elem = CreateJingleVideoContentElem(video, crypto_required); - } - } else if (media->type() == MEDIA_TYPE_DATA) { - const DataContentDescription* data = - static_cast(media); - if (protocol == PROTOCOL_GINGLE) { - return BadWrite("Data channel not supported with Gingle.", error); - } else { - *elem = CreateJingleDataContentElem(data, crypto_required); - } - } else { - return BadWrite("Unknown content type: " + - rtc::ToString(media->type()), error); - } - - return true; -} - -} // namespace cricket diff --git a/webrtc/libjingle/session/media/mediasessionclient.h b/webrtc/libjingle/session/media/mediasessionclient.h deleted file mode 100644 index c80b0a4b4..000000000 --- a/webrtc/libjingle/session/media/mediasessionclient.h +++ /dev/null @@ -1,175 +0,0 @@ -/* - * 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 WEBRTC_LIBJINGLE_SESSION_MEDIA_MEDIASESSIONCLIENT_H_ -#define WEBRTC_LIBJINGLE_SESSION_MEDIA_MEDIASESSIONCLIENT_H_ - -#include -#include -#include -#include - -#include "talk/media/base/cryptoparams.h" -#include "talk/session/media/channelmanager.h" -#include "talk/session/media/mediasession.h" -#include "webrtc/base/messagequeue.h" -#include "webrtc/base/sigslot.h" -#include "webrtc/base/sigslotrepeater.h" -#include "webrtc/base/thread.h" -#include "webrtc/libjingle/session/media/call.h" -#include "webrtc/libjingle/session/sessionclient.h" -#include "webrtc/libjingle/session/sessionmanager.h" -#include "webrtc/p2p/base/sessiondescription.h" - -namespace cricket { - -class Call; - -class MediaSessionClient : public SessionClient, public sigslot::has_slots<> { - public: -#if !defined(DISABLE_MEDIA_ENGINE_FACTORY) - MediaSessionClient(const buzz::Jid& jid, SessionManager *manager); -#endif - // Alternative constructor, allowing injection of media_engine - // and device_manager. - MediaSessionClient(const buzz::Jid& jid, SessionManager *manager, - MediaEngineInterface* media_engine, - DataEngineInterface* data_media_engine, - DeviceManagerInterface* device_manager); - ~MediaSessionClient(); - - const buzz::Jid &jid() const { return jid_; } - SessionManager* session_manager() const { return session_manager_; } - ChannelManager* channel_manager() const { return channel_manager_; } - - // Return mapping of call ids to Calls. - const std::map& calls() const { return calls_; } - - // The settings below combine with the settings on SessionManager to choose - - // whether SDES-SRTP, DTLS-SRTP, or no security should be used. The possible - // combinations are shown in the following table. Note that where either DTLS - // or SDES is possible, DTLS is preferred. Thus to require either SDES or - // DTLS, but not mandate DTLS, set SDES to require and DTLS to enable. - // - // | SDES:Disable | SDES:Enable | SDES:Require | - // ----------------------------------------------------------------| - // DTLS:Disable | No SRTP | SDES Optional | SDES Mandatory | - // DTLS:Enable | DTLS Optional | DTLS/SDES Opt | DTLS/SDES Mand | - // DTLS:Require | DTLS Mandatory | DTLS Mandatory | DTLS Mandatory | - - // Control use of SDES-SRTP. - SecurePolicy secure() const { return desc_factory_.secure(); } - void set_secure(SecurePolicy s) { desc_factory_.set_secure(s); } - - // Control use of multiple sessions in a call. - void set_multisession_enabled(bool multisession_enabled) { - multisession_enabled_ = multisession_enabled; - } - - int GetCapabilities() { return channel_manager_->GetCapabilities(); } - - Call *CreateCall(); - void DestroyCall(Call *call); - - Call *GetFocus(); - void SetFocus(Call *call); - - void JoinCalls(Call *call_to_join, Call *call); - - bool GetAudioInputDevices(std::vector* names) { - return channel_manager_->GetAudioInputDevices(names); - } - bool GetAudioOutputDevices(std::vector* names) { - return channel_manager_->GetAudioOutputDevices(names); - } - bool GetVideoCaptureDevices(std::vector* names) { - return channel_manager_->GetVideoCaptureDevices(names); - } - - bool SetAudioOptions(const std::string& in_name, const std::string& out_name, - const AudioOptions& options) { - return channel_manager_->SetAudioOptions(in_name, out_name, options); - } - bool SetOutputVolume(int level) { - return channel_manager_->SetOutputVolume(level); - } - bool SetCaptureDevice(const std::string& cam_device) { - return channel_manager_->SetCaptureDevice(cam_device); - } - - SessionDescription* CreateOffer(const CallOptions& options) { - return desc_factory_.CreateOffer(options, NULL); - } - SessionDescription* CreateAnswer(const SessionDescription* offer, - const CallOptions& options) { - return desc_factory_.CreateAnswer(offer, options, NULL); - } - - sigslot::signal2 SignalFocus; - sigslot::signal1 SignalCallCreate; - sigslot::signal1 SignalCallDestroy; - sigslot::repeater0<> SignalDevicesChange; - - virtual bool ParseContent(SignalingProtocol protocol, - const buzz::XmlElement* elem, - ContentDescription** content, - ParseError* error); - virtual bool IsWritable(SignalingProtocol protocol, - const ContentDescription* content); - virtual bool WriteContent(SignalingProtocol protocol, - const ContentDescription* content, - buzz::XmlElement** elem, - WriteError* error); - - private: - void Construct(); - void OnSessionCreate(Session *session, bool received_initiate); - void OnSessionState(BaseSession *session, BaseSession::State state); - void OnSessionDestroy(Session *session); - Session *CreateSession(Call *call); - Session *CreateSession(const std::string& id, Call* call); - Call *FindCallByRemoteName(const std::string &remote_name); - - buzz::Jid jid_; - SessionManager* session_manager_; - Call *focus_call_; - ChannelManager *channel_manager_; - MediaSessionDescriptionFactory desc_factory_; - bool multisession_enabled_; - std::map calls_; - - // Maintain a mapping of session id to call. - typedef std::map SessionMap; - SessionMap session_map_; - - friend class Call; -}; - -} // namespace cricket - -#endif // WEBRTC_LIBJINGLE_SESSION_MEDIA_MEDIASESSIONCLIENT_H_ diff --git a/webrtc/libjingle/session/media/mediasessionclient_unittest.cc b/webrtc/libjingle/session/media/mediasessionclient_unittest.cc deleted file mode 100644 index 79fca0135..000000000 --- a/webrtc/libjingle/session/media/mediasessionclient_unittest.cc +++ /dev/null @@ -1,3324 +0,0 @@ -/* - * 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. - */ - -#include -#include - -#include "talk/media/base/fakemediaengine.h" -#include "talk/media/base/testutils.h" -#include "talk/media/devices/fakedevicemanager.h" -#include "webrtc/p2p/base/constants.h" -#include "webrtc/p2p/client/basicportallocator.h" -#include "webrtc/libjingle/session/media/mediasessionclient.h" -#include "webrtc/libjingle/xmllite/xmlbuilder.h" -#include "webrtc/libjingle/xmllite/xmlelement.h" -#include "webrtc/libjingle/xmllite/xmlprinter.h" -#include "webrtc/libjingle/xmpp/constants.h" -#include "webrtc/base/gunit.h" -#include "webrtc/base/logging.h" -#include "webrtc/base/scoped_ptr.h" -#include "webrtc/base/ssladapter.h" - -using cricket::AudioCodec; -using cricket::AudioContentDescription; -using cricket::Codec; -using cricket::DataCodec; -using cricket::DataContentDescription; -using cricket::FeedbackParam; -using cricket::FeedbackParams; -using cricket::VideoCodec; -using cricket::VideoContentDescription; - -// The codecs that our FakeMediaEngine will support. Order is important, since -// the tests check that our messages have codecs in the correct order. -static const cricket::AudioCodec kAudioCodecs[] = { - cricket::AudioCodec(103, "ISAC", 16000, -1, 1, 18), - cricket::AudioCodec(104, "ISAC", 32000, -1, 1, 17), - cricket::AudioCodec(119, "ISACLC", 16000, 40000, 1, 16), - cricket::AudioCodec(99, "speex", 16000, 22000, 1, 15), - cricket::AudioCodec(97, "IPCMWB", 16000, 80000, 1, 14), - cricket::AudioCodec(9, "G722", 8000, 64000, 1, 13), - cricket::AudioCodec(102, "iLBC", 8000, 13300, 1, 12), - cricket::AudioCodec(98, "speex", 8000, 11000, 1, 11), - cricket::AudioCodec(3, "GSM", 8000, 13000, 1, 10), - cricket::AudioCodec(100, "EG711U", 8000, 64000, 1, 9), - cricket::AudioCodec(101, "EG711A", 8000, 64000, 1, 8), - cricket::AudioCodec(0, "PCMU", 8000, 64000, 1, 7), - cricket::AudioCodec(8, "PCMA", 8000, 64000, 1, 6), - cricket::AudioCodec(126, "CN", 32000, 0, 1, 5), - cricket::AudioCodec(105, "CN", 16000, 0, 1, 4), - cricket::AudioCodec(13, "CN", 8000, 0, 1, 3), - cricket::AudioCodec(117, "red", 8000, 0, 1, 2), - cricket::AudioCodec(106, "telephone-event", 8000, 0, 1, 1) -}; - -// The codecs that our FakeMediaEngine will support with a different order of -// supported codecs. -static const cricket::AudioCodec kAudioCodecsDifferentPreference[] = { - cricket::AudioCodec(104, "ISAC", 32000, -1, 1, 17), - cricket::AudioCodec(97, "IPCMWB", 16000, 80000, 1, 14), - cricket::AudioCodec(9, "G722", 8000, 64000, 1, 13), - cricket::AudioCodec(119, "ISACLC", 16000, 40000, 1, 16), - cricket::AudioCodec(103, "ISAC", 16000, -1, 1, 18), - cricket::AudioCodec(99, "speex", 16000, 22000, 1, 15), - cricket::AudioCodec(100, "EG711U", 8000, 64000, 1, 9), - cricket::AudioCodec(101, "EG711A", 8000, 64000, 1, 8), - cricket::AudioCodec(0, "PCMU", 8000, 64000, 1, 7), - cricket::AudioCodec(8, "PCMA", 8000, 64000, 1, 6), - cricket::AudioCodec(102, "iLBC", 8000, 13300, 1, 12), - cricket::AudioCodec(3, "GSM", 8000, 13000, 1, 10), - cricket::AudioCodec(98, "speex", 8000, 11000, 1, 11), - cricket::AudioCodec(126, "CN", 32000, 0, 1, 5), - cricket::AudioCodec(105, "CN", 16000, 0, 1, 4), - cricket::AudioCodec(13, "CN", 8000, 0, 1, 3), - cricket::AudioCodec(117, "red", 8000, 0, 1, 2), - cricket::AudioCodec(106, "telephone-event", 8000, 0, 1, 1) -}; - -static const cricket::VideoCodec kVideoCodecs[] = { - cricket::VideoCodec(96, "H264-SVC", 320, 200, 30, 1) -}; - -static const cricket::DataCodec kDataCodecs[] = { - cricket::DataCodec(127, "google-data", 0) -}; - -const std::string kGingleCryptoOffer = \ - " " \ - " " \ - " " \ - " " \ - " "; - -// Jingle offer does not have any element. -const std::string kJingleCryptoOffer = \ - " " \ - " " \ - " " \ - " "; - - -const std::string kGingleRequiredCryptoOffer = \ - " "\ - " " \ - " " \ - " " \ - " "; - -const std::string kJingleRequiredCryptoOffer = \ - " "\ - " " \ - " " \ - " "; - - -const std::string kGingleUnsupportedCryptoOffer = \ - " " \ - " " \ - " " \ - " " \ - " "; - -const std::string kJingleUnsupportedCryptoOffer = \ - " " \ - " " \ - " " \ - " "; - - -// With unsupported but with required="true" -const std::string kGingleRequiredUnsupportedCryptoOffer = \ - "" \ - " " \ - " " \ - " " \ - " "; - -const std::string kJingleRequiredUnsupportedCryptoOffer = \ - "" \ - " " \ - " " \ - " "; - -const std::string kGingleInitiate( - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " "); - -const std::string kJingleInitiate( - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " "); - -const std::string kJingleInitiateWithRtcpFb( - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " "); - -const std::string kGingleVideoInitiate( - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " "); - -const std::string kJingleVideoInitiate( - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " "); - -const std::string kJingleVideoInitiateWithRtpData( - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " "); - -const std::string kJingleVideoInitiateWithSctpData( - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " "); - -const std::string kJingleVideoInitiateWithBandwidth( - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " 42 " \ - " " \ - " " \ - " " \ - " " \ - " "); - -const std::string kJingleVideoInitiateWithRtcpMux( - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " "); - -// Initiate string with a combination of supported and unsupported codecs -// Should accept the supported ones -const std::string kGingleInitiateSomeUnsupported( - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " "); - -const std::string kJingleInitiateSomeUnsupported( - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " "); - -const std::string kGingleVideoInitiateWithBandwidth( - " " \ - " " \ - " " \ - " " \ - " " \ - " 42 " \ - " " \ - " " \ - " "); - -// Initiate string without any supported codecs. Should send a reject. -const std::string kGingleInitiateNoSupportedAudioCodecs( - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " "); - -const std::string kJingleInitiateNoSupportedAudioCodecs( - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " "); - -// Initiate string without any codecs. Assumes ancient version of Cricket -// and tries a session with ISAC and PCMU -const std::string kGingleInitiateNoAudioCodecs( - " " \ - " " \ - " " \ - " " \ - " " \ - " "); - -const std::string kJingleInitiateNoAudioCodecs( - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " "); - -// The codecs are supported, but not at the given clockrates. Should send -// a reject. -const std::string kGingleInitiateWrongClockrates( - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " "); - -const std::string kJingleInitiateWrongClockrates( - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " "); - -// The codecs are supported, but not with the given number of channels. -// Should send a reject. -const std::string kGingleInitiateWrongChannels( - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " "); - -const std::string kJingleInitiateWrongChannels( - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " "); - -// Initiate with a dynamic codec not using webrtc default payload id. Should -// accept with provided payload id. -const std::string kGingleInitiateDynamicAudioCodecs( - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " "); - -const std::string kJingleInitiateDynamicAudioCodecs( - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " "); - -// Initiate string with nothing but static codec id's. Should accept. -const std::string kGingleInitiateStaticAudioCodecs( - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " "); - -const std::string kJingleInitiateStaticAudioCodecs( - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " "); - -// Initiate with payload type-less codecs. Should reject. -const std::string kGingleInitiateNoPayloadTypes( - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " "); - -const std::string kJingleInitiateNoPayloadTypes( - " " \ - " " \ - " sid='abcdef' initiator='me@domain.com/resource'> " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " "); - -// Initiate with unnamed dynamic codces. Should reject. -const std::string kGingleInitiateDynamicWithoutNames( - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " "); - -const std::string kJingleInitiateDynamicWithoutNames( - " " \ - " " \ - " sid='abcdef' initiator='me@domain.com/resource'> " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " "); - -const uint32 kAudioSsrc = 4294967295U; -const uint32 kVideoSsrc = 87654321; -const uint32 kDataSsrc = 1010101; -// Note that this message does not specify a session ID. It must be populated -// before use. -const std::string kGingleAcceptWithSsrcs( - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " 4294967295 " \ - " 87654321 " \ - " " \ - " " \ - " "); - -const std::string kJingleAcceptWithSsrcs( - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " "); - -const std::string kJingleAcceptWithRtpDataSsrcs( - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " "); - -const std::string kJingleAcceptWithSctpData( - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " " \ - " "); - -std::string JingleView(const std::string& ssrc, - const std::string& width, - const std::string& height, - const std::string& framerate) { - // We have some slightly weird whitespace formatting to make the - // actual XML generated match the expected XML here. - return \ - "" - "" - "" - "" - "" - "" - ""; -} - -std::string JingleStreamAdd(const std::string& content_name, - const std::string& nick, - const std::string& name, - const std::string& ssrc) { - return \ - "" - " " - " " - " " - " " - " " - " " + ssrc + "" - " " - " " - " " - " " - " " - ""; -} - -std::string JingleOutboundStreamRemove(const std::string& sid, - const std::string& content_name, - const std::string& name) { - return \ - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - ""; -} - -std::string JingleOutboundStreamAdd(const std::string& sid, - const std::string& content_name, - const std::string& name, - const std::string& ssrc) { - return \ - "" - "" - "" - "" - "" - "" - "" + ssrc + "" - "" - "" - "" - "" - "" - ""; -} - -std::string JingleStreamAddWithoutSsrc(const std::string& content_name, - const std::string& nick, - const std::string& name) { - return \ - "" - " " - " " - " " - " " - " " - " " - " " - " " - " " - " " - ""; -} - -std::string JingleStreamRemove(const std::string& content_name, - const std::string& nick, - const std::string& name) { - return \ - "" - " " - " " - " " - " " - " " - " " - " " - " " - " " - ""; -} - -// Convenience function to get CallOptions that have audio enabled, -// but not video or data. -static cricket::CallOptions AudioCallOptions() { - cricket::CallOptions options; - options.recv_audio = true; - options.recv_video = false; - options.data_channel_type = cricket::DCT_NONE; - return options; -} - -// Convenience function to get CallOptions that have audio and video -// enabled, but not data. -static cricket::CallOptions VideoCallOptions() { - cricket::CallOptions options; - options.recv_audio = true; - options.recv_video = true; - options.data_channel_type = cricket::DCT_NONE; - return options; -} - -static buzz::XmlElement* CopyElement(const buzz::XmlElement* elem) { - return new buzz::XmlElement(*elem); -} - -static std::string AddEncryption(std::string stanza, std::string encryption) { - std::string::size_type pos = stanza.find(""); - while (pos != std::string::npos) { - stanza = stanza.insert(pos, encryption); - pos = stanza.find("", pos + encryption.length() + 1); - } - return stanza; -} - -static int IntFromJingleCodecParameter(const buzz::XmlElement* parameter, - const std::string& expected_name) { - if (parameter) { - const std::string& actual_name = - parameter->Attr(cricket::QN_PAYLOADTYPE_PARAMETER_NAME); - - EXPECT_EQ(expected_name, actual_name) - << "wrong parameter name. Expected '" - << expected_name << "'. Actually '" - << actual_name << "'."; - - return atoi(parameter->Attr( - cricket::QN_PAYLOADTYPE_PARAMETER_VALUE).c_str()); - } - return 0; -} - -template -static void VerifyCodecFbParams(const FeedbackParams& expected, - const DescriptionClass* desc) { - if (!expected.params().empty()) { - ASSERT_TRUE(desc != NULL); - const std::vector codecs = desc->codecs(); - for (size_t i = 0; i < codecs.size(); ++i) { - EXPECT_EQ(expected, codecs[i].feedback_params); - } - } -} - -// Parses and extracts payload and codec info from test XML. Since -// that XML will be in various contents (Gingle and Jingle), we need an -// abstract parser with one concrete implementation per XML content. -class MediaSessionTestParser { - public: - virtual buzz::XmlElement* ActionFromStanza(buzz::XmlElement* stanza) = 0; - virtual buzz::XmlElement* ContentFromAction(buzz::XmlElement* action) = 0; - virtual buzz::XmlElement* NextContent(buzz::XmlElement* content) = 0; - virtual buzz::XmlElement* PayloadTypeFromContent( - buzz::XmlElement* content) = 0; - virtual buzz::XmlElement* NextFromPayloadType( - buzz::XmlElement* payload_type) = 0; - virtual cricket::AudioCodec AudioCodecFromPayloadType( - const buzz::XmlElement* payload_type) = 0; - virtual cricket::VideoCodec VideoCodecFromPayloadType( - const buzz::XmlElement* payload_type) = 0; - virtual cricket::DataCodec DataCodecFromPayloadType( - const buzz::XmlElement* payload_type) = 0; - virtual buzz::XmlElement* EncryptionFromContent( - buzz::XmlElement* content) = 0; - virtual buzz::XmlElement* NextFromEncryption( - buzz::XmlElement* encryption) = 0; - virtual const buzz::XmlElement* BandwidthFromContent( - buzz::XmlElement* content) = 0; - virtual const buzz::XmlElement* RtcpMuxFromContent( - buzz::XmlElement* content) = 0; - virtual bool ActionIsTerminate(const buzz::XmlElement* action) = 0; - virtual ~MediaSessionTestParser() {} -}; - -class JingleSessionTestParser : public MediaSessionTestParser { - public: - JingleSessionTestParser() {} - - ~JingleSessionTestParser() { - } - - buzz::XmlElement* ActionFromStanza(buzz::XmlElement* stanza) { - return stanza->FirstNamed(cricket::QN_JINGLE); - } - - buzz::XmlElement* ContentFromAction(buzz::XmlElement* action) { - // We need to be able to use multiple contents, but the action - // gets deleted before we can call NextContent, so we need to - // stash away a copy. - action_.reset(CopyElement(action)); - return action_->FirstNamed(cricket::QN_JINGLE_CONTENT); - } - - buzz::XmlElement* NextContent(buzz::XmlElement* content) { - // For some reason, content->NextNamed(cricket::QN_JINGLE_CONTENT) - // doesn't work. - return action_->FirstNamed(cricket::QN_JINGLE_CONTENT) - ->NextNamed(cricket::QN_JINGLE_CONTENT); - } - - buzz::XmlElement* PayloadTypeFromContent(buzz::XmlElement* content) { - buzz::XmlElement* content_desc = - content->FirstNamed(cricket::QN_JINGLE_RTP_CONTENT); - if (!content_desc) - return NULL; - - return content_desc->FirstNamed(cricket::QN_JINGLE_RTP_PAYLOADTYPE); - } - - buzz::XmlElement* NextFromPayloadType(buzz::XmlElement* payload_type) { - return payload_type->NextNamed(cricket::QN_JINGLE_RTP_PAYLOADTYPE); - } - - void ParsePayloadTypeFeedbackParameters(const buzz::XmlElement* element, - FeedbackParams* params) { - const buzz::XmlElement* param = - element->FirstNamed(cricket::QN_JINGLE_RTCP_FB); - for (; param != NULL; - param = param->NextNamed(cricket::QN_JINGLE_RTCP_FB)) { - std::string type = param->Attr(cricket::QN_TYPE); - std::string subtype = param->Attr(cricket::QN_SUBTYPE); - if (!type.empty()) { - params->Add(FeedbackParam(type, subtype)); - } - } - } - - cricket::AudioCodec AudioCodecFromPayloadType( - const buzz::XmlElement* payload_type) { - int id = 0; - if (payload_type->HasAttr(cricket::QN_ID)) - id = atoi(payload_type->Attr(cricket::QN_ID).c_str()); - - std::string name; - if (payload_type->HasAttr(cricket::QN_NAME)) - name = payload_type->Attr(cricket::QN_NAME); - - int clockrate = 0; - if (payload_type->HasAttr(cricket::QN_CLOCKRATE)) - clockrate = atoi(payload_type->Attr(cricket::QN_CLOCKRATE).c_str()); - - int bitrate = IntFromJingleCodecParameter( - payload_type->FirstNamed(cricket::QN_PARAMETER), "bitrate"); - - int channels = 1; - if (payload_type->HasAttr(cricket::QN_CHANNELS)) - channels = atoi(payload_type->Attr( - cricket::QN_CHANNELS).c_str()); - - AudioCodec codec = AudioCodec(id, name, clockrate, bitrate, channels, 0); - ParsePayloadTypeFeedbackParameters(payload_type, &codec.feedback_params); - return codec; - } - - cricket::VideoCodec VideoCodecFromPayloadType( - const buzz::XmlElement* payload_type) { - int id = 0; - if (payload_type->HasAttr(cricket::QN_ID)) - id = atoi(payload_type->Attr(cricket::QN_ID).c_str()); - - std::string name; - if (payload_type->HasAttr(cricket::QN_NAME)) - name = payload_type->Attr(cricket::QN_NAME); - - int width = 0; - int height = 0; - int framerate = 0; - const buzz::XmlElement* param = - payload_type->FirstNamed(cricket::QN_PARAMETER); - if (param) { - width = IntFromJingleCodecParameter(param, "width"); - param = param->NextNamed(cricket::QN_PARAMETER); - if (param) { - height = IntFromJingleCodecParameter(param, "height"); - param = param->NextNamed(cricket::QN_PARAMETER); - if (param) { - framerate = IntFromJingleCodecParameter(param, "framerate"); - } - } - } - VideoCodec codec = VideoCodec(id, name, width, height, framerate, 0); - ParsePayloadTypeFeedbackParameters(payload_type, &codec.feedback_params); - return codec; - } - - cricket::DataCodec DataCodecFromPayloadType( - const buzz::XmlElement* payload_type) { - int id = 0; - if (payload_type->HasAttr(cricket::QN_ID)) - id = atoi(payload_type->Attr(cricket::QN_ID).c_str()); - - std::string name; - if (payload_type->HasAttr(cricket::QN_NAME)) - name = payload_type->Attr(cricket::QN_NAME); - - DataCodec codec = DataCodec(id, name, 0); - ParsePayloadTypeFeedbackParameters(payload_type, &codec.feedback_params); - return codec; - } - - bool ActionIsTerminate(const buzz::XmlElement* action) { - return (action->HasAttr(cricket::QN_ACTION) && - action->Attr(cricket::QN_ACTION) == "session-terminate"); - } - - buzz::XmlElement* EncryptionFromContent(buzz::XmlElement* content) { - buzz::XmlElement* content_desc = - content->FirstNamed(cricket::QN_JINGLE_RTP_CONTENT); - if (!content_desc) - return NULL; - - return content_desc->FirstNamed(cricket::QN_ENCRYPTION); - } - - buzz::XmlElement* NextFromEncryption(buzz::XmlElement* encryption) { - return encryption->NextNamed(cricket::QN_ENCRYPTION); - } - - const buzz::XmlElement* BandwidthFromContent(buzz::XmlElement* content) { - buzz::XmlElement* content_desc = - content->FirstNamed(cricket::QN_JINGLE_RTP_CONTENT); - if (!content_desc) - return NULL; - - return content_desc->FirstNamed(cricket::QN_JINGLE_RTP_BANDWIDTH); - } - - const buzz::XmlElement* RtcpMuxFromContent(buzz::XmlElement* content) { - return content->FirstNamed(cricket::QN_JINGLE_RTCP_MUX); - } - - private: - rtc::scoped_ptr action_; -}; - -class GingleSessionTestParser : public MediaSessionTestParser { - public: - GingleSessionTestParser() : found_content_count_(0) {} - - buzz::XmlElement* ActionFromStanza(buzz::XmlElement* stanza) { - return stanza->FirstNamed(cricket::QN_GINGLE_SESSION); - } - - buzz::XmlElement* ContentFromAction(buzz::XmlElement* session) { - buzz::XmlElement* content = - session->FirstNamed(cricket::QN_GINGLE_AUDIO_CONTENT); - if (content == NULL) - content = session->FirstNamed(cricket::QN_GINGLE_VIDEO_CONTENT); - return content; - } - - // Assumes contents are in order of audio, and then video. - buzz::XmlElement* NextContent(buzz::XmlElement* content) { - found_content_count_++; - return content; - } - - buzz::XmlElement* PayloadTypeFromContent(buzz::XmlElement* content) { - if (found_content_count_ > 0) { - return content->FirstNamed(cricket::QN_GINGLE_VIDEO_PAYLOADTYPE); - } else { - return content->FirstNamed(cricket::QN_GINGLE_AUDIO_PAYLOADTYPE); - } - } - - buzz::XmlElement* NextFromPayloadType(buzz::XmlElement* payload_type) { - if (found_content_count_ > 0) { - return payload_type->NextNamed(cricket::QN_GINGLE_VIDEO_PAYLOADTYPE); - } else { - return payload_type->NextNamed(cricket::QN_GINGLE_AUDIO_PAYLOADTYPE); - } - } - - cricket::AudioCodec AudioCodecFromPayloadType( - const buzz::XmlElement* payload_type) { - int id = 0; - if (payload_type->HasAttr(cricket::QN_ID)) - id = atoi(payload_type->Attr(cricket::QN_ID).c_str()); - - std::string name; - if (payload_type->HasAttr(cricket::QN_NAME)) - name = payload_type->Attr(cricket::QN_NAME); - - int clockrate = 0; - if (payload_type->HasAttr(cricket::QN_CLOCKRATE)) - clockrate = atoi(payload_type->Attr(cricket::QN_CLOCKRATE).c_str()); - - int bitrate = 0; - if (payload_type->HasAttr(cricket::QN_BITRATE)) - bitrate = atoi(payload_type->Attr(cricket::QN_BITRATE).c_str()); - - int channels = 1; - if (payload_type->HasAttr(cricket::QN_CHANNELS)) - channels = atoi(payload_type->Attr(cricket::QN_CHANNELS).c_str()); - - return cricket::AudioCodec(id, name, clockrate, bitrate, channels, 0); - } - - cricket::VideoCodec VideoCodecFromPayloadType( - const buzz::XmlElement* payload_type) { - int id = 0; - if (payload_type->HasAttr(cricket::QN_ID)) - id = atoi(payload_type->Attr(cricket::QN_ID).c_str()); - - std::string name; - if (payload_type->HasAttr(cricket::QN_NAME)) - name = payload_type->Attr(cricket::QN_NAME); - - int width = 0; - if (payload_type->HasAttr(cricket::QN_WIDTH)) - width = atoi(payload_type->Attr(cricket::QN_WIDTH).c_str()); - - int height = 0; - if (payload_type->HasAttr(cricket::QN_HEIGHT)) - height = atoi(payload_type->Attr(cricket::QN_HEIGHT).c_str()); - - int framerate = 1; - if (payload_type->HasAttr(cricket::QN_FRAMERATE)) - framerate = atoi(payload_type->Attr(cricket::QN_FRAMERATE).c_str()); - - return cricket::VideoCodec(id, name, width, height, framerate, 0); - } - - cricket::DataCodec DataCodecFromPayloadType( - const buzz::XmlElement* payload_type) { - // Gingle can't do data codecs. - return cricket::DataCodec(0, "", 0); - } - - buzz::XmlElement* EncryptionFromContent( - buzz::XmlElement* content) { - return content->FirstNamed(cricket::QN_ENCRYPTION); - } - - buzz::XmlElement* NextFromEncryption(buzz::XmlElement* encryption) { - return encryption->NextNamed(cricket::QN_ENCRYPTION); - } - - const buzz::XmlElement* BandwidthFromContent(buzz::XmlElement* content) { - return content->FirstNamed(cricket::QN_GINGLE_VIDEO_BANDWIDTH); - } - - const buzz::XmlElement* RtcpMuxFromContent(buzz::XmlElement* content) { - return NULL; - } - - bool ActionIsTerminate(const buzz::XmlElement* session) { - return (session->HasAttr(buzz::QN_TYPE) && - session->Attr(buzz::QN_TYPE) == "terminate"); - } - - int found_content_count_; -}; - -class MediaSessionClientTest : public sigslot::has_slots<> { - public: - explicit MediaSessionClientTest(MediaSessionTestParser* parser, - cricket::SignalingProtocol initial_protocol) { - nm_ = new rtc::BasicNetworkManager(); - pa_ = new cricket::BasicPortAllocator(nm_); - sm_ = new cricket::SessionManager(pa_, NULL); - fme_ = new cricket::FakeMediaEngine(); - fdme_ = new cricket::FakeDataEngine(); - - FeedbackParams params_nack_fir; - params_nack_fir.Add(FeedbackParam(cricket::kRtcpFbParamCcm, - cricket::kRtcpFbCcmParamFir)); - params_nack_fir.Add(FeedbackParam(cricket::kRtcpFbParamNack)); - FeedbackParams params_nack; - params_nack.Add(FeedbackParam(cricket::kRtcpFbParamNack)); - - std::vector - audio_codecs(kAudioCodecs, kAudioCodecs + ARRAY_SIZE(kAudioCodecs)); - SetCodecFeedbackParams(&audio_codecs, params_nack); - fme_->SetAudioCodecs(audio_codecs); - std::vector - video_codecs(kVideoCodecs, kVideoCodecs + ARRAY_SIZE(kVideoCodecs)); - SetCodecFeedbackParams(&video_codecs, params_nack_fir); - fme_->SetVideoCodecs(video_codecs); - std::vector - data_codecs(kDataCodecs, kDataCodecs + ARRAY_SIZE(kDataCodecs)); - SetCodecFeedbackParams(&data_codecs, params_nack); - fdme_->SetDataCodecs(data_codecs); - - client_ = new cricket::MediaSessionClient( - buzz::Jid("user@domain.com/resource"), sm_, - fme_, fdme_, new cricket::FakeDeviceManager()); - client_->session_manager()->SignalOutgoingMessage.connect( - this, &MediaSessionClientTest::OnSendStanza); - client_->session_manager()->SignalSessionCreate.connect( - this, &MediaSessionClientTest::OnSessionCreate); - client_->SignalCallCreate.connect( - this, &MediaSessionClientTest::OnCallCreate); - client_->SignalCallDestroy.connect( - this, &MediaSessionClientTest::OnCallDestroy); - - call_ = NULL; - parser_ = parser; - initial_protocol_ = initial_protocol; - expect_incoming_crypto_ = false; - expect_outgoing_crypto_ = false; - expected_video_bandwidth_ = cricket::kAutoBandwidth; - expected_video_rtcp_mux_ = false; - } - - ~MediaSessionClientTest() { - delete client_; - delete sm_; - delete pa_; - delete nm_; - delete parser_; - ClearStanzas(); - } - - buzz::XmlElement* ActionFromStanza(buzz::XmlElement* stanza) { - return parser_->ActionFromStanza(stanza); - } - - buzz::XmlElement* ContentFromAction(buzz::XmlElement* action) { - return parser_->ContentFromAction(action); - } - - buzz::XmlElement* PayloadTypeFromContent(buzz::XmlElement* payload) { - return parser_->PayloadTypeFromContent(payload); - } - - buzz::XmlElement* NextFromPayloadType(buzz::XmlElement* payload_type) { - return parser_->NextFromPayloadType(payload_type); - } - - buzz::XmlElement* EncryptionFromContent(buzz::XmlElement* content) { - return parser_->EncryptionFromContent(content); - } - - buzz::XmlElement* NextFromEncryption(buzz::XmlElement* encryption) { - return parser_->NextFromEncryption(encryption); - } - - cricket::AudioCodec AudioCodecFromPayloadType( - const buzz::XmlElement* payload_type) { - return parser_->AudioCodecFromPayloadType(payload_type); - } - - cricket::VideoCodec VideoCodecFromPayloadType( - const buzz::XmlElement* payload_type) { - return parser_->VideoCodecFromPayloadType(payload_type); - } - - cricket::DataCodec DataCodecFromPayloadType( - const buzz::XmlElement* payload_type) { - return parser_->DataCodecFromPayloadType(payload_type); - } - - const AudioContentDescription* GetFirstAudioContentDescription( - const cricket::SessionDescription* sdesc) { - const cricket::ContentInfo* content = - cricket::GetFirstAudioContent(sdesc); - if (content == NULL) - return NULL; - return static_cast(content->description); - } - - const cricket::VideoContentDescription* GetFirstVideoContentDescription( - const cricket::SessionDescription* sdesc) { - const cricket::ContentInfo* content = - cricket::GetFirstVideoContent(sdesc); - if (content == NULL) - return NULL; - return static_cast( - content->description); - } - - void CheckCryptoFromGoodIncomingInitiate(const cricket::Session* session) { - ASSERT_TRUE(session != NULL); - const AudioContentDescription* content = - GetFirstAudioContentDescription(session->remote_description()); - ASSERT_TRUE(content != NULL); - ASSERT_EQ(2U, content->cryptos().size()); - ASSERT_EQ(145, content->cryptos()[0].tag); - ASSERT_EQ("AES_CM_128_HMAC_SHA1_32", content->cryptos()[0].cipher_suite); - ASSERT_EQ("inline:hsWuSQJxx7przmb8HM+ZkeNcG3HezSNID7LmfDa9", - content->cryptos()[0].key_params); - ASSERT_EQ(51, content->cryptos()[1].tag); - ASSERT_EQ("AES_CM_128_HMAC_SHA1_80", content->cryptos()[1].cipher_suite); - ASSERT_EQ("inline:J4lfdUL8W1F7TNJKcbuygaQuA429SJy2e9JctPUy", - content->cryptos()[1].key_params); - } - - void CheckCryptoForGoodOutgoingAccept(const cricket::Session* session) { - const AudioContentDescription* content = - GetFirstAudioContentDescription(session->local_description()); - ASSERT_EQ(1U, content->cryptos().size()); - ASSERT_EQ(145, content->cryptos()[0].tag); - ASSERT_EQ("AES_CM_128_HMAC_SHA1_32", content->cryptos()[0].cipher_suite); - ASSERT_EQ(47U, content->cryptos()[0].key_params.size()); - } - - void CheckBadCryptoFromIncomingInitiate(const cricket::Session* session) { - const AudioContentDescription* content = - GetFirstAudioContentDescription(session->remote_description()); - ASSERT_EQ(1U, content->cryptos().size()); - ASSERT_EQ(145, content->cryptos()[0].tag); - ASSERT_EQ("NOT_SUPPORTED", content->cryptos()[0].cipher_suite); - ASSERT_EQ("inline:hsWuSQJxx7przmb8HM+ZkeNcG3HezSNID7LmfDa9", - content->cryptos()[0].key_params); - } - - void CheckNoCryptoForOutgoingAccept(const cricket::Session* session) { - const AudioContentDescription* content = - GetFirstAudioContentDescription(session->local_description()); - ASSERT_TRUE(content->cryptos().empty()); - } - - void CheckRtcpFb(const cricket::SessionDescription* sdesc) { - VerifyCodecFbParams(expected_audio_fb_params_, - GetFirstAudioContentDescription(sdesc)); - - VerifyCodecFbParams(expected_video_fb_params_, - GetFirstVideoContentDescription(sdesc)); - - VerifyCodecFbParams(expected_data_fb_params_, - GetFirstDataContentDescription(sdesc)); - } - - void CheckVideoBandwidth(int expected_bandwidth, - const cricket::SessionDescription* sdesc) { - const cricket::VideoContentDescription* video = - GetFirstVideoContentDescription(sdesc); - if (video != NULL) { - ASSERT_EQ(expected_bandwidth, video->bandwidth()); - } - } - - void CheckVideoRtcpMux(bool expected_video_rtcp_mux, - const cricket::SessionDescription* sdesc) { - const cricket::VideoContentDescription* video = - GetFirstVideoContentDescription(sdesc); - if (video != NULL) { - ASSERT_EQ(expected_video_rtcp_mux, video->rtcp_mux()); - } - } - - virtual void CheckRtpDataContent(buzz::XmlElement* content) { - if (initial_protocol_) { - // Gingle can not write out data content. - return; - } - - buzz::XmlElement* e = PayloadTypeFromContent(content); - ASSERT_TRUE(e != NULL); - cricket::DataCodec codec = DataCodecFromPayloadType(e); - EXPECT_EQ(127, codec.id); - EXPECT_EQ("google-data", codec.name); - EXPECT_EQ(expected_data_fb_params_, codec.feedback_params); - - CheckDataRtcpMux(true, call_->sessions()[0]->local_description()); - CheckDataRtcpMux(true, call_->sessions()[0]->remote_description()); - if (expect_outgoing_crypto_) { - content = parser_->NextContent(content); - buzz::XmlElement* encryption = EncryptionFromContent(content); - ASSERT_TRUE(encryption != NULL); - // TODO(pthatcher): Check encryption parameters? - } - } - - virtual void CheckSctpDataContent(buzz::XmlElement* content) { - if (initial_protocol_) { - // Gingle can not write out data content. - return; - } - - buzz::XmlElement* payload_type = PayloadTypeFromContent(content); - ASSERT_TRUE(payload_type == NULL); - buzz::XmlElement* encryption = EncryptionFromContent(content); - ASSERT_TRUE(encryption == NULL); - // TODO(pthatcher): Check for . - } - - void CheckDataRtcpMux(bool expected_data_rtcp_mux, - const cricket::SessionDescription* sdesc) { - const cricket::DataContentDescription* data = - GetFirstDataContentDescription(sdesc); - if (data != NULL) { - ASSERT_EQ(expected_data_rtcp_mux, data->rtcp_mux()); - } - } - - void CheckAudioSsrcForIncomingAccept(const cricket::Session* session) { - const AudioContentDescription* audio = - GetFirstAudioContentDescription(session->remote_description()); - ASSERT_TRUE(audio != NULL); - ASSERT_EQ(kAudioSsrc, audio->first_ssrc()); - } - - void CheckVideoSsrcForIncomingAccept(const cricket::Session* session) { - const cricket::VideoContentDescription* video = - GetFirstVideoContentDescription(session->remote_description()); - ASSERT_TRUE(video != NULL); - ASSERT_EQ(kVideoSsrc, video->first_ssrc()); - } - - void CheckDataSsrcForIncomingAccept(const cricket::Session* session) { - const cricket::DataContentDescription* data = - GetFirstDataContentDescription(session->remote_description()); - ASSERT_TRUE(data != NULL); - ASSERT_EQ(kDataSsrc, data->first_ssrc()); - } - - void TestGoodIncomingInitiate(const std::string& initiate_string, - const cricket::CallOptions& options, - buzz::XmlElement** element) { - *element = NULL; - - rtc::scoped_ptr el( - buzz::XmlElement::ForStr(initiate_string)); - client_->session_manager()->OnIncomingMessage(el.get()); - ASSERT_TRUE(call_ != NULL); - ASSERT_TRUE(call_->sessions()[0] != NULL); - ASSERT_EQ(cricket::Session::STATE_RECEIVEDINITIATE, - call_->sessions()[0]->state()); - ASSERT_EQ(1U, stanzas_.size()); - ASSERT_TRUE(buzz::QN_IQ == stanzas_[0]->Name()); - ASSERT_TRUE(stanzas_[0]->HasAttr(buzz::QN_TYPE)); - ASSERT_EQ(std::string(buzz::STR_RESULT), stanzas_[0]->Attr(buzz::QN_TYPE)); - ClearStanzas(); - CheckVideoBandwidth(expected_video_bandwidth_, - call_->sessions()[0]->remote_description()); - CheckVideoRtcpMux(expected_video_rtcp_mux_, - call_->sessions()[0]->remote_description()); - CheckRtcpFb(call_->sessions()[0]->remote_description()); - if (expect_incoming_crypto_) { - CheckCryptoFromGoodIncomingInitiate(call_->sessions()[0]); - } - - // TODO(pthatcher): Add tests for sending in accept. - call_->AcceptSession(call_->sessions()[0], options); - ASSERT_EQ(cricket::Session::STATE_SENTACCEPT, - call_->sessions()[0]->state()); - ASSERT_EQ(1U, stanzas_.size()); - ASSERT_TRUE(buzz::QN_IQ == stanzas_[0]->Name()); - ASSERT_TRUE(stanzas_[0]->HasAttr(buzz::QN_TYPE)); - ASSERT_EQ(std::string(buzz::STR_SET), stanzas_[0]->Attr(buzz::QN_TYPE)); - - buzz::XmlElement* e = ActionFromStanza(stanzas_[0]); - ASSERT_TRUE(e != NULL); - ASSERT_TRUE(ContentFromAction(e) != NULL); - *element = CopyElement(ContentFromAction(e)); - ASSERT_TRUE(*element != NULL); - ClearStanzas(); - if (expect_outgoing_crypto_) { - CheckCryptoForGoodOutgoingAccept(call_->sessions()[0]); - } - - if (options.data_channel_type == cricket::DCT_RTP) { - CheckDataRtcpMux(true, call_->sessions()[0]->local_description()); - CheckDataRtcpMux(true, call_->sessions()[0]->remote_description()); - // TODO(pthatcher): Check rtcpmux and crypto? - } - - call_->Terminate(); - ASSERT_EQ(cricket::Session::STATE_SENTTERMINATE, - call_->sessions()[0]->state()); - ASSERT_EQ(1U, stanzas_.size()); - ASSERT_TRUE(buzz::QN_IQ == stanzas_[0]->Name()); - ASSERT_TRUE(stanzas_[0]->HasAttr(buzz::QN_TYPE)); - ASSERT_EQ(std::string(buzz::STR_SET), stanzas_[0]->Attr(buzz::QN_TYPE)); - e = ActionFromStanza(stanzas_[0]); - ASSERT_TRUE(e != NULL); - ASSERT_TRUE(parser_->ActionIsTerminate(e)); - ClearStanzas(); - } - - void TestRejectOffer(const std::string &initiate_string, - const cricket::CallOptions& options, - buzz::XmlElement** element) { - *element = NULL; - - rtc::scoped_ptr el( - buzz::XmlElement::ForStr(initiate_string)); - client_->session_manager()->OnIncomingMessage(el.get()); - ASSERT_TRUE(call_ != NULL); - ASSERT_TRUE(call_->sessions()[0] != NULL); - ASSERT_EQ(cricket::Session::STATE_RECEIVEDINITIATE, - call_->sessions()[0]->state()); - ASSERT_EQ(1U, stanzas_.size()); - ASSERT_TRUE(buzz::QN_IQ == stanzas_[0]->Name()); - ASSERT_TRUE(stanzas_[0]->HasAttr(buzz::QN_TYPE)); - ASSERT_EQ(std::string(buzz::STR_RESULT), stanzas_[0]->Attr(buzz::QN_TYPE)); - ClearStanzas(); - - call_->AcceptSession(call_->sessions()[0], options); - ASSERT_EQ(cricket::Session::STATE_SENTACCEPT, - call_->sessions()[0]->state()); - ASSERT_EQ(1U, stanzas_.size()); - ASSERT_TRUE(buzz::QN_IQ == stanzas_[0]->Name()); - ASSERT_TRUE(stanzas_[0]->HasAttr(buzz::QN_TYPE)); - ASSERT_EQ(std::string(buzz::STR_SET), stanzas_[0]->Attr(buzz::QN_TYPE)); - - buzz::XmlElement* e = ActionFromStanza(stanzas_[0]); - ASSERT_TRUE(e != NULL); - ASSERT_TRUE(ContentFromAction(e) != NULL); - *element = CopyElement(ContentFromAction(e)); - ASSERT_TRUE(*element != NULL); - ClearStanzas(); - - buzz::XmlElement* content = *element; - // The NextContent method actually returns the second content. So we - // can't handle the case when audio, video and data are all enabled. But - // since we are testing rejection, it won't be the case. - if (options.has_audio()) { - ASSERT_TRUE(content != NULL); - ASSERT_EQ("test audio", content->Attr(buzz::QName("", "name"))); - content = parser_->NextContent(content); - } - - if (options.has_video()) { - ASSERT_TRUE(content != NULL); - ASSERT_EQ("test video", content->Attr(buzz::QName("", "name"))); - content = parser_->NextContent(content); - } - - if (options.has_data()) { - ASSERT_TRUE(content != NULL); - ASSERT_EQ("test data", content->Attr(buzz::QName("", "name"))); - content = parser_->NextContent(content); - } - - call_->Terminate(); - ASSERT_EQ(cricket::Session::STATE_SENTTERMINATE, - call_->sessions()[0]->state()); - ASSERT_EQ(1U, stanzas_.size()); - ASSERT_TRUE(buzz::QN_IQ == stanzas_[0]->Name()); - ASSERT_TRUE(stanzas_[0]->HasAttr(buzz::QN_TYPE)); - ASSERT_EQ(std::string(buzz::STR_SET), stanzas_[0]->Attr(buzz::QN_TYPE)); - e = ActionFromStanza(stanzas_[0]); - ASSERT_TRUE(e != NULL); - ASSERT_TRUE(parser_->ActionIsTerminate(e)); - ClearStanzas(); - } - - void TestBadIncomingInitiate(const std::string& initiate_string) { - rtc::scoped_ptr el( - buzz::XmlElement::ForStr(initiate_string)); - client_->session_manager()->OnIncomingMessage(el.get()); - ASSERT_TRUE(call_ != NULL); - ASSERT_TRUE(call_->sessions()[0] != NULL); - ASSERT_EQ(cricket::Session::STATE_SENTREJECT, - call_->sessions()[0]->state()); - ASSERT_EQ(2U, stanzas_.size()); - ASSERT_TRUE(buzz::QN_IQ == stanzas_[0]->Name()); - ASSERT_TRUE(stanzas_[1]->HasAttr(buzz::QN_TYPE)); - ASSERT_EQ(std::string(buzz::STR_RESULT), stanzas_[1]->Attr(buzz::QN_TYPE)); - ClearStanzas(); - } - - void VerifyAudioCodec(const AudioCodec& codec, int id, - const std::string& name, int clockrate, - int bitrate, int channels) { - ASSERT_EQ(id, codec.id); - ASSERT_EQ(name, codec.name); - ASSERT_EQ(clockrate, codec.clockrate); - ASSERT_EQ(bitrate, codec.bitrate); - ASSERT_EQ(channels, codec.channels); - ASSERT_EQ(expected_audio_fb_params_, codec.feedback_params); - } - - void TestGoodOutgoingInitiate(const cricket::CallOptions& options) { - if (initial_protocol_ == cricket::PROTOCOL_JINGLE) { - // rtcp fb is only implemented for jingle. - ExpectRtcpFb(); - } - - client_->CreateCall(); - ASSERT_TRUE(call_ != NULL); - call_->InitiateSession(buzz::Jid("me@mydomain.com"), - buzz::Jid("me@mydomain.com"), options); - ASSERT_TRUE(call_->sessions()[0] != NULL); - ASSERT_EQ(cricket::Session::STATE_SENTINITIATE, - call_->sessions()[0]->state()); - ASSERT_EQ(1U, stanzas_.size()); - ASSERT_TRUE(buzz::QN_IQ == stanzas_[0]->Name()); - ASSERT_TRUE(stanzas_[0]->HasAttr(buzz::QN_TYPE)); - ASSERT_EQ(std::string(buzz::STR_SET), stanzas_[0]->Attr(buzz::QN_TYPE)); - buzz::XmlElement* action = ActionFromStanza(stanzas_[0]); - ASSERT_TRUE(action != NULL); - buzz::XmlElement* content = ContentFromAction(action); - ASSERT_TRUE(content != NULL); - - buzz::XmlElement* e = PayloadTypeFromContent(content); - ASSERT_TRUE(e != NULL); - cricket::AudioCodec codec = AudioCodecFromPayloadType(e); - VerifyAudioCodec(codec, 103, "ISAC", 16000, 0, 1); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e != NULL); - codec = AudioCodecFromPayloadType(e); - VerifyAudioCodec(codec, 104, "ISAC", 32000, 0, 1); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e != NULL); - codec = AudioCodecFromPayloadType(e); - VerifyAudioCodec(codec, 119, "ISACLC", 16000, 40000, 1); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e != NULL); - codec = AudioCodecFromPayloadType(e); - VerifyAudioCodec(codec, 99, "speex", 16000, 22000, 1); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e != NULL); - codec = AudioCodecFromPayloadType(e); - VerifyAudioCodec(codec, 97, "IPCMWB", 16000, 80000, 1); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e != NULL); - codec = AudioCodecFromPayloadType(e); - VerifyAudioCodec(codec, 9, "G722", 8000, 64000, 1); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e != NULL); - codec = AudioCodecFromPayloadType(e); - VerifyAudioCodec(codec, 102, "iLBC", 8000, 13300, 1); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e != NULL); - codec = AudioCodecFromPayloadType(e); - VerifyAudioCodec(codec, 98, "speex", 8000, 11000, 1); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e != NULL); - codec = AudioCodecFromPayloadType(e); - VerifyAudioCodec(codec, 3, "GSM", 8000, 13000, 1); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e != NULL); - codec = AudioCodecFromPayloadType(e); - VerifyAudioCodec(codec, 100, "EG711U", 8000, 64000, 1); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e != NULL); - codec = AudioCodecFromPayloadType(e); - VerifyAudioCodec(codec, 101, "EG711A", 8000, 64000, 1); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e != NULL); - codec = AudioCodecFromPayloadType(e); - VerifyAudioCodec(codec, 0, "PCMU", 8000, 64000, 1); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e != NULL); - codec = AudioCodecFromPayloadType(e); - VerifyAudioCodec(codec, 8, "PCMA", 8000, 64000, 1); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e != NULL); - codec = AudioCodecFromPayloadType(e); - VerifyAudioCodec(codec, 126, "CN", 32000, 0, 1); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e != NULL); - codec = AudioCodecFromPayloadType(e); - VerifyAudioCodec(codec, 105, "CN", 16000, 0, 1); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e != NULL); - codec = AudioCodecFromPayloadType(e); - VerifyAudioCodec(codec, 13, "CN", 8000, 0, 1); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e != NULL); - codec = AudioCodecFromPayloadType(e); - VerifyAudioCodec(codec, 117, "red", 8000, 0, 1); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e != NULL); - codec = AudioCodecFromPayloadType(e); - VerifyAudioCodec(codec, 106, "telephone-event", 8000, 0, 1); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e == NULL); - - if (expect_outgoing_crypto_) { - buzz::XmlElement* encryption = EncryptionFromContent(content); - ASSERT_TRUE(encryption != NULL); - - if (client_->secure() == cricket::SEC_REQUIRED) { - ASSERT_TRUE(cricket::GetXmlAttr( - encryption, cricket::QN_ENCRYPTION_REQUIRED, false)); - } - - if (content->Name().Namespace() == cricket::NS_GINGLE_AUDIO) { - e = encryption->FirstNamed(cricket::QN_GINGLE_AUDIO_CRYPTO_USAGE); - ASSERT_TRUE(e != NULL); - ASSERT_TRUE( - e->NextNamed(cricket::QN_GINGLE_AUDIO_CRYPTO_USAGE) == NULL); - ASSERT_TRUE( - e->FirstNamed(cricket::QN_GINGLE_VIDEO_CRYPTO_USAGE) == NULL); - } - - e = encryption->FirstNamed(cricket::QN_CRYPTO); - ASSERT_TRUE(e != NULL); - ASSERT_EQ("0", e->Attr(cricket::QN_CRYPTO_TAG)); - ASSERT_EQ("AES_CM_128_HMAC_SHA1_32", e->Attr(cricket::QN_CRYPTO_SUITE)); - std::string key_0 = e->Attr(cricket::QN_CRYPTO_KEY_PARAMS); - ASSERT_EQ(47U, key_0.length()); - ASSERT_EQ("inline:", key_0.substr(0, 7)); - - e = e->NextNamed(cricket::QN_CRYPTO); - ASSERT_TRUE(e != NULL); - ASSERT_EQ("1", e->Attr(cricket::QN_CRYPTO_TAG)); - ASSERT_EQ("AES_CM_128_HMAC_SHA1_80", e->Attr(cricket::QN_CRYPTO_SUITE)); - std::string key_1 = e->Attr(cricket::QN_CRYPTO_KEY_PARAMS); - ASSERT_EQ(47U, key_1.length()); - ASSERT_EQ("inline:", key_1.substr(0, 7)); - ASSERT_NE(key_0, key_1); - - encryption = NextFromEncryption(encryption); - ASSERT_TRUE(encryption == NULL); - } - - if (options.has_video()) { - CheckVideoBandwidth(options.video_bandwidth, - call_->sessions()[0]->local_description()); - CheckVideoRtcpMux(expected_video_rtcp_mux_, - call_->sessions()[0]->remote_description()); - content = parser_->NextContent(content); - const buzz::XmlElement* bandwidth = - parser_->BandwidthFromContent(content); - if (options.video_bandwidth == cricket::kAutoBandwidth) { - ASSERT_TRUE(bandwidth == NULL); - } else { - ASSERT_TRUE(bandwidth != NULL); - ASSERT_EQ("AS", bandwidth->Attr(buzz::QName("", "type"))); - ASSERT_EQ(rtc::ToString(options.video_bandwidth / 1000), - bandwidth->BodyText()); - } - - buzz::XmlElement* e = PayloadTypeFromContent(content); - ASSERT_TRUE(e != NULL); - VideoCodec codec = VideoCodecFromPayloadType(e); - VideoCodec expected_codec = kVideoCodecs[0]; - expected_codec.preference = codec.preference; - expected_codec.feedback_params = expected_video_fb_params_; - EXPECT_EQ(expected_codec, codec); - } - - if (options.data_channel_type == cricket::DCT_RTP) { - content = parser_->NextContent(content); - CheckRtpDataContent(content); - } - - if (options.data_channel_type == cricket::DCT_SCTP) { - content = parser_->NextContent(content); - CheckSctpDataContent(content); - } - - ClearStanzas(); - } - - void TestHasAllSupportedAudioCodecs(buzz::XmlElement* e) { - ASSERT_TRUE(e != NULL); - - e = PayloadTypeFromContent(e); - ASSERT_TRUE(e != NULL); - cricket::AudioCodec codec = AudioCodecFromPayloadType(e); - ASSERT_EQ(103, codec.id); - ASSERT_EQ("ISAC", codec.name); - ASSERT_EQ(16000, codec.clockrate); - ASSERT_EQ(1, codec.channels); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e != NULL); - codec = AudioCodecFromPayloadType(e); - ASSERT_EQ(104, codec.id); - ASSERT_EQ("ISAC", codec.name); - ASSERT_EQ(32000, codec.clockrate); - ASSERT_EQ(1, codec.channels); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e != NULL); - codec = AudioCodecFromPayloadType(e); - ASSERT_EQ(119, codec.id); - ASSERT_EQ("ISACLC", codec.name); - ASSERT_EQ(16000, codec.clockrate); - ASSERT_EQ(40000, codec.bitrate); - ASSERT_EQ(1, codec.channels); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e != NULL); - codec = AudioCodecFromPayloadType(e); - ASSERT_EQ(99, codec.id); - ASSERT_EQ("speex", codec.name); - ASSERT_EQ(16000, codec.clockrate); - ASSERT_EQ(22000, codec.bitrate); - ASSERT_EQ(1, codec.channels); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e != NULL); - codec = AudioCodecFromPayloadType(e); - ASSERT_EQ(97, codec.id); - ASSERT_EQ("IPCMWB", codec.name); - ASSERT_EQ(16000, codec.clockrate); - ASSERT_EQ(80000, codec.bitrate); - ASSERT_EQ(1, codec.channels); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e != NULL); - codec = AudioCodecFromPayloadType(e); - ASSERT_EQ(9, codec.id); - ASSERT_EQ("G722", codec.name); - ASSERT_EQ(8000, codec.clockrate); - ASSERT_EQ(64000, codec.bitrate); - ASSERT_EQ(1, codec.channels); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e != NULL); - codec = AudioCodecFromPayloadType(e); - ASSERT_EQ(102, codec.id); - ASSERT_EQ("iLBC", codec.name); - ASSERT_EQ(8000, codec.clockrate); - ASSERT_EQ(13300, codec.bitrate); - ASSERT_EQ(1, codec.channels); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e != NULL); - codec = AudioCodecFromPayloadType(e); - ASSERT_EQ(98, codec.id); - ASSERT_EQ("speex", codec.name); - ASSERT_EQ(8000, codec.clockrate); - ASSERT_EQ(11000, codec.bitrate); - ASSERT_EQ(1, codec.channels); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e != NULL); - codec = AudioCodecFromPayloadType(e); - ASSERT_EQ(3, codec.id); - ASSERT_EQ("GSM", codec.name); - ASSERT_EQ(8000, codec.clockrate); - ASSERT_EQ(13000, codec.bitrate); - ASSERT_EQ(1, codec.channels); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e != NULL); - codec = AudioCodecFromPayloadType(e); - ASSERT_EQ(100, codec.id); - ASSERT_EQ("EG711U", codec.name); - ASSERT_EQ(8000, codec.clockrate); - ASSERT_EQ(64000, codec.bitrate); - ASSERT_EQ(1, codec.channels); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e != NULL); - codec = AudioCodecFromPayloadType(e); - ASSERT_EQ(101, codec.id); - ASSERT_EQ("EG711A", codec.name); - ASSERT_EQ(8000, codec.clockrate); - ASSERT_EQ(64000, codec.bitrate); - ASSERT_EQ(1, codec.channels); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e != NULL); - codec = AudioCodecFromPayloadType(e); - ASSERT_EQ(0, codec.id); - ASSERT_EQ("PCMU", codec.name); - ASSERT_EQ(8000, codec.clockrate); - ASSERT_EQ(64000, codec.bitrate); - ASSERT_EQ(1, codec.channels); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e != NULL); - codec = AudioCodecFromPayloadType(e); - ASSERT_EQ(8, codec.id); - ASSERT_EQ("PCMA", codec.name); - ASSERT_EQ(8000, codec.clockrate); - ASSERT_EQ(64000, codec.bitrate); - ASSERT_EQ(1, codec.channels); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e != NULL); - codec = AudioCodecFromPayloadType(e); - ASSERT_EQ(126, codec.id); - ASSERT_EQ("CN", codec.name); - ASSERT_EQ(32000, codec.clockrate); - ASSERT_EQ(1, codec.channels); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e != NULL); - codec = AudioCodecFromPayloadType(e); - ASSERT_EQ(105, codec.id); - ASSERT_EQ("CN", codec.name); - ASSERT_EQ(16000, codec.clockrate); - ASSERT_EQ(1, codec.channels); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e != NULL); - codec = AudioCodecFromPayloadType(e); - ASSERT_EQ(13, codec.id); - ASSERT_EQ("CN", codec.name); - ASSERT_EQ(8000, codec.clockrate); - ASSERT_EQ(1, codec.channels); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e != NULL); - codec = AudioCodecFromPayloadType(e); - ASSERT_EQ(117, codec.id); - ASSERT_EQ("red", codec.name); - ASSERT_EQ(8000, codec.clockrate); - ASSERT_EQ(1, codec.channels); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e != NULL); - codec = AudioCodecFromPayloadType(e); - ASSERT_EQ(106, codec.id); - ASSERT_EQ("telephone-event", codec.name); - ASSERT_EQ(8000, codec.clockrate); - ASSERT_EQ(1, codec.channels); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e == NULL); - } - - void TestCodecsOfVideoInitiate(buzz::XmlElement* content) { - ASSERT_TRUE(content != NULL); - buzz::XmlElement* payload_type = PayloadTypeFromContent(content); - ASSERT_TRUE(payload_type != NULL); - cricket::AudioCodec codec = AudioCodecFromPayloadType(payload_type); - ASSERT_EQ(103, codec.id); - ASSERT_EQ("ISAC", codec.name); - ASSERT_EQ(16000, codec.clockrate); - ASSERT_EQ(1, codec.channels); - - content = parser_->NextContent(content); - ASSERT_TRUE(content != NULL); - payload_type = PayloadTypeFromContent(content); - ASSERT_TRUE(payload_type != NULL); - cricket::VideoCodec vcodec = - parser_->VideoCodecFromPayloadType(payload_type); - ASSERT_EQ(99, vcodec.id); - ASSERT_EQ("H264-SVC", vcodec.name); - ASSERT_EQ(320, vcodec.width); - ASSERT_EQ(200, vcodec.height); - ASSERT_EQ(30, vcodec.framerate); - } - - void TestHasAudioCodecsFromInitiateSomeUnsupported(buzz::XmlElement* e) { - ASSERT_TRUE(e != NULL); - e = PayloadTypeFromContent(e); - ASSERT_TRUE(e != NULL); - - cricket::AudioCodec codec = AudioCodecFromPayloadType(e); - ASSERT_EQ(103, codec.id); - ASSERT_EQ("ISAC", codec.name); - ASSERT_EQ(16000, codec.clockrate); - ASSERT_EQ(1, codec.channels); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e != NULL); - codec = AudioCodecFromPayloadType(e); - ASSERT_EQ(100, codec.id); - ASSERT_EQ("EG711U", codec.name); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e != NULL); - codec = AudioCodecFromPayloadType(e); - ASSERT_EQ(101, codec.id); - ASSERT_EQ("EG711A", codec.name); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e != NULL); - codec = AudioCodecFromPayloadType(e); - ASSERT_EQ(0, codec.id); - ASSERT_EQ("PCMU", codec.name); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e != NULL); - codec = AudioCodecFromPayloadType(e); - ASSERT_EQ(13, codec.id); - ASSERT_EQ("CN", codec.name); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e == NULL); - } - - void TestHasAudioCodecsFromInitiateDynamicAudioCodecs( - buzz::XmlElement* e) { - ASSERT_TRUE(e != NULL); - e = PayloadTypeFromContent(e); - ASSERT_TRUE(e != NULL); - - cricket::AudioCodec codec = AudioCodecFromPayloadType(e); - ASSERT_EQ(123, codec.id); - ASSERT_EQ(16000, codec.clockrate); - ASSERT_EQ(1, codec.channels); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e == NULL); - } - - void TestHasDefaultAudioCodecs(buzz::XmlElement* e) { - ASSERT_TRUE(e != NULL); - e = PayloadTypeFromContent(e); - ASSERT_TRUE(e != NULL); - - cricket::AudioCodec codec = AudioCodecFromPayloadType(e); - ASSERT_EQ(103, codec.id); - ASSERT_EQ("ISAC", codec.name); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e != NULL); - codec = AudioCodecFromPayloadType(e); - ASSERT_EQ(0, codec.id); - ASSERT_EQ("PCMU", codec.name); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e == NULL); - } - - void TestHasAudioCodecsFromInitiateStaticAudioCodecs( - buzz::XmlElement* e) { - ASSERT_TRUE(e != NULL); - e = PayloadTypeFromContent(e); - ASSERT_TRUE(e != NULL); - - cricket::AudioCodec codec = AudioCodecFromPayloadType(e); - ASSERT_EQ(3, codec.id); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e != NULL); - codec = AudioCodecFromPayloadType(e); - ASSERT_EQ(0, codec.id); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e != NULL); - codec = AudioCodecFromPayloadType(e); - ASSERT_EQ(8, codec.id); - - e = NextFromPayloadType(e); - ASSERT_TRUE(e == NULL); - } - - void TestGingleInitiateWithUnsupportedCrypto( - const std::string &initiate_string, - buzz::XmlElement** element) { - *element = NULL; - - rtc::scoped_ptr el( - buzz::XmlElement::ForStr(initiate_string)); - client_->session_manager()->OnIncomingMessage(el.get()); - - ASSERT_EQ(cricket::Session::STATE_RECEIVEDINITIATE, - call_->sessions()[0]->state()); - ClearStanzas(); - CheckBadCryptoFromIncomingInitiate(call_->sessions()[0]); - - call_->AcceptSession(call_->sessions()[0], cricket::CallOptions()); - ClearStanzas(); - CheckNoCryptoForOutgoingAccept(call_->sessions()[0]); - - call_->Terminate(); - ASSERT_EQ(cricket::Session::STATE_SENTTERMINATE, - call_->sessions()[0]->state()); - ClearStanzas(); - } - - void TestIncomingAcceptWithSsrcs( - const std::string& accept_string, - cricket::CallOptions& options) { - client_->CreateCall(); - ASSERT_TRUE(call_ != NULL); - - call_->InitiateSession(buzz::Jid("me@mydomain.com"), - buzz::Jid("me@mydomain.com"), options); - ASSERT_TRUE(call_->sessions()[0] != NULL); - ASSERT_EQ(cricket::Session::STATE_SENTINITIATE, - call_->sessions()[0]->state()); - ASSERT_EQ(1U, stanzas_.size()); - ASSERT_TRUE(buzz::QN_IQ == stanzas_[0]->Name()); - ASSERT_TRUE(stanzas_[0]->HasAttr(buzz::QN_TYPE)); - ASSERT_EQ(std::string(buzz::STR_SET), stanzas_[0]->Attr(buzz::QN_TYPE)); - buzz::XmlElement* action = ActionFromStanza(stanzas_[0]); - ASSERT_TRUE(action != NULL); - buzz::XmlElement* content = ContentFromAction(action); - ASSERT_TRUE(content != NULL); - if (initial_protocol_ == cricket::PROTOCOL_JINGLE) { - buzz::XmlElement* content_desc = - content->FirstNamed(cricket::QN_JINGLE_RTP_CONTENT); - ASSERT_TRUE(content_desc != NULL); - ASSERT_EQ("", content_desc->Attr(cricket::QN_SSRC)); - } - ClearStanzas(); - - // We need to insert the session ID into the session accept message. - rtc::scoped_ptr el( - buzz::XmlElement::ForStr(accept_string)); - const std::string sid = call_->sessions()[0]->id(); - if (initial_protocol_ == cricket::PROTOCOL_JINGLE) { - buzz::XmlElement* jingle = el->FirstNamed(cricket::QN_JINGLE); - jingle->SetAttr(cricket::QN_SID, sid); - } else { - buzz::XmlElement* session = el->FirstNamed(cricket::QN_GINGLE_SESSION); - session->SetAttr(cricket::QN_ID, sid); - } - - client_->session_manager()->OnIncomingMessage(el.get()); - - ASSERT_EQ(cricket::Session::STATE_RECEIVEDACCEPT, - call_->sessions()[0]->state()); - ASSERT_EQ(1U, stanzas_.size()); - ASSERT_TRUE(buzz::QN_IQ == stanzas_[0]->Name()); - ASSERT_TRUE(stanzas_[0]->HasAttr(buzz::QN_TYPE)); - ASSERT_EQ(std::string(buzz::STR_RESULT), stanzas_[0]->Attr(buzz::QN_TYPE)); - ClearStanzas(); - - CheckAudioSsrcForIncomingAccept(call_->sessions()[0]); - CheckVideoSsrcForIncomingAccept(call_->sessions()[0]); - if (options.data_channel_type == cricket::DCT_RTP) { - CheckDataSsrcForIncomingAccept(call_->sessions()[0]); - } - // TODO(pthatcher): Check kDataSid if DCT_SCTP. - // const uint32 kDataSid = 0; - } - - size_t ClearStanzas() { - size_t size = stanzas_.size(); - for (size_t i = 0; i < size; i++) { - delete stanzas_[i]; - } - stanzas_.clear(); - return size; - } - - buzz::XmlElement* SetJingleSid(buzz::XmlElement* stanza) { - buzz::XmlElement* jingle = - stanza->FirstNamed(cricket::QN_JINGLE); - jingle->SetAttr(cricket::QN_SID, call_->sessions()[0]->id()); - return stanza; - } - - void TestSendVideoStreamUpdate() { - cricket::CallOptions options = VideoCallOptions(); - options.is_muc = true; - - client_->CreateCall(); - call_->InitiateSession(buzz::Jid("me@mydomain.com"), - buzz::Jid("me@mydomain.com"), options); - ClearStanzas(); - - cricket::StreamParams stream; - stream.id = "test-stream"; - stream.ssrcs.push_back(1001); - rtc::scoped_ptr expected_stream_add( - buzz::XmlElement::ForStr( - JingleOutboundStreamAdd( - call_->sessions()[0]->id(), - "video", stream.id, "1001"))); - rtc::scoped_ptr expected_stream_remove( - buzz::XmlElement::ForStr( - JingleOutboundStreamRemove( - call_->sessions()[0]->id(), - "video", stream.id))); - - call_->SendVideoStreamUpdate(call_->sessions()[0], - call_->CreateVideoStreamUpdate(stream)); - ASSERT_EQ(1U, stanzas_.size()); - EXPECT_EQ(expected_stream_add->Str(), stanzas_[0]->Str()); - ClearStanzas(); - - stream.ssrcs.clear(); - call_->SendVideoStreamUpdate(call_->sessions()[0], - call_->CreateVideoStreamUpdate(stream)); - ASSERT_EQ(1U, stanzas_.size()); - EXPECT_EQ(expected_stream_remove->Str(), stanzas_[0]->Str()); - ClearStanzas(); - } - - void TestStreamsUpdateAndViewRequests() { - cricket::CallOptions options = VideoCallOptions(); - options.is_muc = true; - - client_->CreateCall(); - call_->InitiateSession(buzz::Jid("me@mydomain.com"), - buzz::Jid("me@mydomain.com"), options); - ASSERT_EQ(1U, ClearStanzas()); - ASSERT_EQ(0U, last_streams_added_.audio().size()); - ASSERT_EQ(0U, last_streams_added_.video().size()); - ASSERT_EQ(0U, last_streams_removed_.audio().size()); - ASSERT_EQ(0U, last_streams_removed_.video().size()); - - rtc::scoped_ptr accept_stanza( - buzz::XmlElement::ForStr(kJingleAcceptWithSsrcs)); - SetJingleSid(accept_stanza.get()); - client_->session_manager()->OnIncomingMessage(accept_stanza.get()); - ASSERT_EQ(cricket::Session::STATE_RECEIVEDACCEPT, - call_->sessions()[0]->state()); - ASSERT_EQ(1U, stanzas_.size()); - ASSERT_EQ(std::string(buzz::STR_RESULT), stanzas_[0]->Attr(buzz::QN_TYPE)); - ClearStanzas(); - // Need to clear the added streams, because they are populated when - // receiving an accept message now. - last_streams_added_.mutable_video()->clear(); - last_streams_added_.mutable_audio()->clear(); - - call_->sessions()[0]->SetState(cricket::Session::STATE_INPROGRESS); - - rtc::scoped_ptr streams_stanza( - buzz::XmlElement::ForStr( - JingleStreamAdd("video", "Bob", "video1", "ABC"))); - SetJingleSid(streams_stanza.get()); - client_->session_manager()->OnIncomingMessage(streams_stanza.get()); - // First one is ignored because of bad syntax. - ASSERT_EQ(1U, stanzas_.size()); - // TODO(pthatcher): Figure out how to make this an ERROR rather than RESULT. - ASSERT_EQ(std::string(buzz::STR_ERROR), stanzas_[0]->Attr(buzz::QN_TYPE)); - ClearStanzas(); - ASSERT_EQ(0U, last_streams_added_.audio().size()); - ASSERT_EQ(0U, last_streams_added_.video().size()); - ASSERT_EQ(0U, last_streams_removed_.audio().size()); - ASSERT_EQ(0U, last_streams_removed_.video().size()); - - streams_stanza.reset(buzz::XmlElement::ForStr( - JingleStreamAdd("audio", "Bob", "audio1", "1234"))); - SetJingleSid(streams_stanza.get()); - client_->session_manager()->OnIncomingMessage(streams_stanza.get()); - ASSERT_EQ(1U, last_streams_added_.audio().size()); - ASSERT_EQ("Bob", last_streams_added_.audio()[0].groupid); - ASSERT_EQ(1U, last_streams_added_.audio()[0].ssrcs.size()); - ASSERT_EQ(1234U, last_streams_added_.audio()[0].first_ssrc()); - - // Ignores adds without ssrcs. - streams_stanza.reset(buzz::XmlElement::ForStr( - JingleStreamAddWithoutSsrc("audio", "Bob", "audioX"))); - SetJingleSid(streams_stanza.get()); - client_->session_manager()->OnIncomingMessage(streams_stanza.get()); - ASSERT_EQ(1U, last_streams_added_.audio().size()); - ASSERT_EQ(1234U, last_streams_added_.audio()[0].first_ssrc()); - - // Ignores stream updates with unknown content names. (Don't terminate). - streams_stanza.reset(buzz::XmlElement::ForStr( - JingleStreamAddWithoutSsrc("foo", "Bob", "foo"))); - SetJingleSid(streams_stanza.get()); - client_->session_manager()->OnIncomingMessage(streams_stanza.get()); - - streams_stanza.reset(buzz::XmlElement::ForStr( - JingleStreamAdd("audio", "Joe", "audio1", "2468"))); - SetJingleSid(streams_stanza.get()); - client_->session_manager()->OnIncomingMessage(streams_stanza.get()); - ASSERT_EQ(1U, last_streams_added_.audio().size()); - ASSERT_EQ("Joe", last_streams_added_.audio()[0].groupid); - ASSERT_EQ(1U, last_streams_added_.audio()[0].ssrcs.size()); - ASSERT_EQ(2468U, last_streams_added_.audio()[0].first_ssrc()); - - streams_stanza.reset(buzz::XmlElement::ForStr( - JingleStreamAdd("video", "Bob", "video1", "5678"))); - SetJingleSid(streams_stanza.get()); - client_->session_manager()->OnIncomingMessage(streams_stanza.get()); - ASSERT_EQ(1U, last_streams_added_.video().size()); - ASSERT_EQ("Bob", last_streams_added_.video()[0].groupid); - ASSERT_EQ(1U, last_streams_added_.video()[0].ssrcs.size()); - ASSERT_EQ(5678U, last_streams_added_.video()[0].first_ssrc()); - - // We're testing that a "duplicate" is effectively ignored. - last_streams_added_.mutable_video()->clear(); - last_streams_removed_.mutable_video()->clear(); - streams_stanza.reset(buzz::XmlElement::ForStr( - JingleStreamAdd("video", "Bob", "video1", "5678"))); - SetJingleSid(streams_stanza.get()); - client_->session_manager()->OnIncomingMessage(streams_stanza.get()); - ASSERT_EQ(0U, last_streams_added_.video().size()); - ASSERT_EQ(0U, last_streams_removed_.video().size()); - - streams_stanza.reset(buzz::XmlElement::ForStr( - JingleStreamAdd("video", "Bob", "video2", "5679"))); - SetJingleSid(streams_stanza.get()); - client_->session_manager()->OnIncomingMessage(streams_stanza.get()); - ASSERT_EQ(1U, last_streams_added_.video().size()); - ASSERT_EQ("Bob", last_streams_added_.video()[0].groupid); - ASSERT_EQ(1U, last_streams_added_.video()[0].ssrcs.size()); - ASSERT_EQ(5679U, last_streams_added_.video()[0].first_ssrc()); - - cricket::FakeVoiceMediaChannel* voice_channel = fme_->GetVoiceChannel(0); - ASSERT_TRUE(voice_channel != NULL); - ASSERT_TRUE(voice_channel->HasRecvStream(1234U)); - ASSERT_TRUE(voice_channel->HasRecvStream(2468U)); - cricket::FakeVideoMediaChannel* video_channel = fme_->GetVideoChannel(0); - ASSERT_TRUE(video_channel != NULL); - ASSERT_TRUE(video_channel->HasRecvStream(5678U)); - ClearStanzas(); - - cricket::ViewRequest viewRequest; - cricket::StaticVideoView staticVideoView( - cricket::StreamSelector(5678U), 640, 480, 30); - viewRequest.static_video_views.push_back(staticVideoView); - rtc::scoped_ptr expected_view_elem( - buzz::XmlElement::ForStr(JingleView("5678", "640", "480", "30"))); - SetJingleSid(expected_view_elem.get()); - - ASSERT_TRUE( - call_->SendViewRequest(call_->sessions()[0], viewRequest)); - ASSERT_EQ(1U, stanzas_.size()); - ASSERT_EQ(expected_view_elem->Str(), stanzas_[0]->Str()); - ClearStanzas(); - - streams_stanza.reset(buzz::XmlElement::ForStr( - JingleStreamRemove("audio", "Bob", "audio1"))); - SetJingleSid(streams_stanza.get()); - client_->session_manager()->OnIncomingMessage(streams_stanza.get()); - ASSERT_EQ(1U, last_streams_removed_.audio().size()); - ASSERT_EQ(1U, last_streams_removed_.audio()[0].ssrcs.size()); - EXPECT_EQ(1234U, last_streams_removed_.audio()[0].first_ssrc()); - - streams_stanza.reset(buzz::XmlElement::ForStr( - JingleStreamRemove("video", "Bob", "video1"))); - SetJingleSid(streams_stanza.get()); - client_->session_manager()->OnIncomingMessage(streams_stanza.get()); - ASSERT_EQ(1U, last_streams_removed_.video().size()); - ASSERT_EQ(1U, last_streams_removed_.video()[0].ssrcs.size()); - EXPECT_EQ(5678U, last_streams_removed_.video()[0].first_ssrc()); - - streams_stanza.reset(buzz::XmlElement::ForStr( - JingleStreamRemove("video", "Bob", "video2"))); - SetJingleSid(streams_stanza.get()); - client_->session_manager()->OnIncomingMessage(streams_stanza.get()); - ASSERT_EQ(1U, last_streams_removed_.video().size()); - ASSERT_EQ(1U, last_streams_removed_.video()[0].ssrcs.size()); - EXPECT_EQ(5679U, last_streams_removed_.video()[0].first_ssrc()); - - // Duplicate removal: should be ignored. - last_streams_removed_.mutable_audio()->clear(); - streams_stanza.reset(buzz::XmlElement::ForStr( - JingleStreamRemove("audio", "Bob", "audio1"))); - SetJingleSid(streams_stanza.get()); - client_->session_manager()->OnIncomingMessage(streams_stanza.get()); - ASSERT_EQ(0U, last_streams_removed_.audio().size()); - - // Duplicate removal: should be ignored. - last_streams_removed_.mutable_video()->clear(); - streams_stanza.reset(buzz::XmlElement::ForStr( - JingleStreamRemove("video", "Bob", "video1"))); - SetJingleSid(streams_stanza.get()); - client_->session_manager()->OnIncomingMessage(streams_stanza.get()); - ASSERT_EQ(0U, last_streams_removed_.video().size()); - - voice_channel = fme_->GetVoiceChannel(0); - ASSERT_TRUE(voice_channel != NULL); - ASSERT_FALSE(voice_channel->HasRecvStream(1234U)); - ASSERT_TRUE(voice_channel->HasRecvStream(2468U)); - video_channel = fme_->GetVideoChannel(0); - ASSERT_TRUE(video_channel != NULL); - ASSERT_FALSE(video_channel->HasRecvStream(5678U)); - - // Fails because ssrc is now invalid. - ASSERT_FALSE( - call_->SendViewRequest(call_->sessions()[0], viewRequest)); - - ClearStanzas(); - } - - void MakeSignalingSecure(cricket::SecurePolicy secure) { - client_->set_secure(secure); - } - - void ExpectCrypto(cricket::SecurePolicy secure) { - MakeSignalingSecure(secure); - expect_incoming_crypto_ = true; -#ifdef HAVE_SRTP - expect_outgoing_crypto_ = true; -#endif - } - - void ExpectVideoBandwidth(int bandwidth) { - expected_video_bandwidth_ = bandwidth; - } - - void ExpectVideoRtcpMux(bool rtcp_mux) { - expected_video_rtcp_mux_ = rtcp_mux; - } - - template - void SetCodecFeedbackParams(std::vector* codecs, - const FeedbackParams& fb_params) { - for (size_t i = 0; i < codecs->size(); ++i) { - codecs->at(i).feedback_params = fb_params; - } - } - - void ExpectRtcpFb() { - FeedbackParams params_nack_fir; - params_nack_fir.Add(FeedbackParam(cricket::kRtcpFbParamCcm, - cricket::kRtcpFbCcmParamFir)); - params_nack_fir.Add(FeedbackParam(cricket::kRtcpFbParamNack)); - - FeedbackParams params_nack; - params_nack.Add(FeedbackParam(cricket::kRtcpFbParamNack)); - - expected_audio_fb_params_ = params_nack; - expected_video_fb_params_ = params_nack_fir; - expected_data_fb_params_ = params_nack; - } - - cricket::FakeMediaEngine* fme() { return fme_; } - - private: - void OnSendStanza(cricket::SessionManager* manager, - const buzz::XmlElement* stanza) { - LOG(LS_INFO) << stanza->Str(); - stanzas_.push_back(new buzz::XmlElement(*stanza)); - } - - void OnSessionCreate(cricket::Session* session, bool initiate) { - session->set_current_protocol(initial_protocol_); - } - - void OnCallCreate(cricket::Call *call) { - call_ = call; - call->SignalMediaStreamsUpdate.connect( - this, &MediaSessionClientTest::OnMediaStreamsUpdate); - } - - void OnCallDestroy(cricket::Call *call) { - call_ = NULL; - } - - void OnMediaStreamsUpdate(cricket::Call *call, - cricket::Session *session, - const cricket::MediaStreams& added, - const cricket::MediaStreams& removed) { - last_streams_added_.CopyFrom(added); - last_streams_removed_.CopyFrom(removed); - } - - rtc::NetworkManager* nm_; - cricket::PortAllocator* pa_; - cricket::SessionManager* sm_; - cricket::FakeMediaEngine* fme_; - cricket::FakeDataEngine* fdme_; - cricket::MediaSessionClient* client_; - - cricket::Call* call_; - std::vector stanzas_; - MediaSessionTestParser* parser_; - cricket::SignalingProtocol initial_protocol_; - bool expect_incoming_crypto_; - bool expect_outgoing_crypto_; - int expected_video_bandwidth_; - bool expected_video_rtcp_mux_; - FeedbackParams expected_audio_fb_params_; - FeedbackParams expected_video_fb_params_; - FeedbackParams expected_data_fb_params_; - cricket::MediaStreams last_streams_added_; - cricket::MediaStreams last_streams_removed_; -}; - -MediaSessionClientTest* GingleTest() { - return new MediaSessionClientTest(new GingleSessionTestParser(), - cricket::PROTOCOL_GINGLE); -} - -MediaSessionClientTest* JingleTest() { - return new MediaSessionClientTest(new JingleSessionTestParser(), - cricket::PROTOCOL_JINGLE); -} - -class MediaSessionTest : public ::testing::Test {}; - -TEST_F(MediaSessionTest, JingleGoodInitiateWithRtcpFb) { - rtc::scoped_ptr test(JingleTest()); - rtc::scoped_ptr elem; - - cricket::CallOptions options = VideoCallOptions(); - options.data_channel_type = cricket::DCT_SCTP; - test->ExpectRtcpFb(); - test->TestGoodIncomingInitiate( - kJingleInitiateWithRtcpFb, options, elem.use()); -} - -TEST_F(MediaSessionTest, JingleGoodVideoInitiate) { - rtc::scoped_ptr test(JingleTest()); - rtc::scoped_ptr elem; - test->TestGoodIncomingInitiate( - kJingleVideoInitiate, VideoCallOptions(), elem.use()); - test->TestCodecsOfVideoInitiate(elem.get()); -} - -TEST_F(MediaSessionTest, JingleGoodVideoInitiateWithBandwidth) { - rtc::scoped_ptr test(JingleTest()); - rtc::scoped_ptr elem; - test->ExpectVideoBandwidth(42000); - test->TestGoodIncomingInitiate( - kJingleVideoInitiateWithBandwidth, VideoCallOptions(), elem.use()); -} - -TEST_F(MediaSessionTest, JingleGoodVideoInitiateWithRtcpMux) { - rtc::scoped_ptr test(JingleTest()); - rtc::scoped_ptr elem; - test->ExpectVideoRtcpMux(true); - test->TestGoodIncomingInitiate( - kJingleVideoInitiateWithRtcpMux, VideoCallOptions(), elem.use()); -} - -TEST_F(MediaSessionTest, JingleGoodVideoInitiateWithRtpData) { - rtc::scoped_ptr test(JingleTest()); - rtc::scoped_ptr elem; - cricket::CallOptions options = VideoCallOptions(); - options.data_channel_type = cricket::DCT_RTP; - test->TestGoodIncomingInitiate( - AddEncryption(kJingleVideoInitiateWithRtpData, kJingleCryptoOffer), - options, - elem.use()); -} - -TEST_F(MediaSessionTest, JingleGoodVideoInitiateWithSctpData) { - rtc::scoped_ptr test(JingleTest()); - rtc::scoped_ptr elem; - cricket::CallOptions options = VideoCallOptions(); - options.data_channel_type = cricket::DCT_SCTP; - test->TestGoodIncomingInitiate(kJingleVideoInitiateWithSctpData, - options, - elem.use()); -} - -TEST_F(MediaSessionTest, JingleRejectAudio) { - rtc::scoped_ptr test(JingleTest()); - rtc::scoped_ptr elem; - cricket::CallOptions options = VideoCallOptions(); - options.recv_audio = false; - options.data_channel_type = cricket::DCT_RTP; - test->TestRejectOffer(kJingleVideoInitiateWithRtpData, options, elem.use()); -} - -TEST_F(MediaSessionTest, JingleRejectVideo) { - rtc::scoped_ptr test(JingleTest()); - rtc::scoped_ptr elem; - cricket::CallOptions options = AudioCallOptions(); - options.data_channel_type = cricket::DCT_RTP; - test->TestRejectOffer(kJingleVideoInitiateWithRtpData, options, elem.use()); -} - -TEST_F(MediaSessionTest, JingleRejectData) { - rtc::scoped_ptr test(JingleTest()); - rtc::scoped_ptr elem; - test->TestRejectOffer( - kJingleVideoInitiateWithRtpData, VideoCallOptions(), elem.use()); -} - -TEST_F(MediaSessionTest, JingleRejectVideoAndData) { - rtc::scoped_ptr test(JingleTest()); - rtc::scoped_ptr elem; - test->TestRejectOffer( - kJingleVideoInitiateWithRtpData, AudioCallOptions(), elem.use()); -} - -TEST_F(MediaSessionTest, JingleGoodInitiateAllSupportedAudioCodecs) { - rtc::scoped_ptr test(JingleTest()); - rtc::scoped_ptr elem; - test->TestGoodIncomingInitiate( - kJingleInitiate, AudioCallOptions(), elem.use()); - test->TestHasAllSupportedAudioCodecs(elem.get()); -} - -// Changes the codecs that our FakeMediaEngine will support with a different -// preference order than the incoming offer. -// Verifies the answer accepts the preference order of the remote peer. -TEST_F(MediaSessionTest, JingleGoodInitiateDifferentPreferenceAudioCodecs) { - rtc::scoped_ptr test(JingleTest()); - test->fme()->SetAudioCodecs(MAKE_VECTOR(kAudioCodecsDifferentPreference)); - rtc::scoped_ptr elem; - test->TestGoodIncomingInitiate( - kJingleInitiate, AudioCallOptions(), elem.use()); - test->TestHasAllSupportedAudioCodecs(elem.get()); -} - -TEST_F(MediaSessionTest, JingleGoodInitiateSomeUnsupportedAudioCodecs) { - rtc::scoped_ptr test(JingleTest()); - rtc::scoped_ptr elem; - test->TestGoodIncomingInitiate( - kJingleInitiateSomeUnsupported, AudioCallOptions(), elem.use()); - test->TestHasAudioCodecsFromInitiateSomeUnsupported(elem.get()); -} - -TEST_F(MediaSessionTest, JingleGoodInitiateDynamicAudioCodecs) { - rtc::scoped_ptr test(JingleTest()); - rtc::scoped_ptr elem; - test->TestGoodIncomingInitiate( - kJingleInitiateDynamicAudioCodecs, AudioCallOptions(), elem.use()); - test->TestHasAudioCodecsFromInitiateDynamicAudioCodecs(elem.get()); -} - -TEST_F(MediaSessionTest, JingleGoodInitiateStaticAudioCodecs) { - rtc::scoped_ptr test(JingleTest()); - rtc::scoped_ptr elem; - test->TestGoodIncomingInitiate( - kJingleInitiateStaticAudioCodecs, AudioCallOptions(), elem.use()); - test->TestHasAudioCodecsFromInitiateStaticAudioCodecs(elem.get()); -} - -TEST_F(MediaSessionTest, JingleBadInitiateNoAudioCodecs) { - rtc::scoped_ptr test(JingleTest()); - test->TestBadIncomingInitiate(kJingleInitiateNoAudioCodecs); -} - -TEST_F(MediaSessionTest, JingleBadInitiateNoSupportedAudioCodecs) { - rtc::scoped_ptr test(JingleTest()); - test->TestBadIncomingInitiate(kJingleInitiateNoSupportedAudioCodecs); -} - -TEST_F(MediaSessionTest, JingleBadInitiateWrongClockrates) { - rtc::scoped_ptr test(JingleTest()); - test->TestBadIncomingInitiate(kJingleInitiateWrongClockrates); -} - -TEST_F(MediaSessionTest, JingleBadInitiateWrongChannels) { - rtc::scoped_ptr test(JingleTest()); - test->TestBadIncomingInitiate(kJingleInitiateWrongChannels); -} - -TEST_F(MediaSessionTest, JingleBadInitiateNoPayloadTypes) { - rtc::scoped_ptr test(JingleTest()); - test->TestBadIncomingInitiate(kJingleInitiateNoPayloadTypes); -} - -TEST_F(MediaSessionTest, JingleBadInitiateDynamicWithoutNames) { - rtc::scoped_ptr test(JingleTest()); - test->TestBadIncomingInitiate(kJingleInitiateDynamicWithoutNames); -} - -TEST_F(MediaSessionTest, JingleGoodOutgoingInitiate) { - rtc::scoped_ptr test(JingleTest()); - test->TestGoodOutgoingInitiate(AudioCallOptions()); -} - -TEST_F(MediaSessionTest, JingleGoodOutgoingInitiateWithBandwidth) { - rtc::scoped_ptr test(JingleTest()); - cricket::CallOptions options = VideoCallOptions(); - options.video_bandwidth = 42000; - test->TestGoodOutgoingInitiate(options); -} - -TEST_F(MediaSessionTest, JingleGoodOutgoingInitiateWithRtcpMux) { - rtc::scoped_ptr test(JingleTest()); - cricket::CallOptions options = VideoCallOptions(); - options.rtcp_mux_enabled = true; - test->TestGoodOutgoingInitiate(options); -} - -TEST_F(MediaSessionTest, JingleGoodOutgoingInitiateWithRtpData) { - rtc::scoped_ptr test(JingleTest()); - cricket::CallOptions options; - options.data_channel_type = cricket::DCT_RTP; - test->ExpectCrypto(cricket::SEC_ENABLED); - test->TestGoodOutgoingInitiate(options); -} - -TEST_F(MediaSessionTest, JingleGoodOutgoingInitiateWithSctpData) { - rtc::scoped_ptr test(JingleTest()); - cricket::CallOptions options; - options.data_channel_type = cricket::DCT_SCTP; - test->TestGoodOutgoingInitiate(options); -} - -// Crypto related tests. - -// Offer has crypto but the session is not secured, just ignore it. -TEST_F(MediaSessionTest, JingleInitiateWithCryptoIsIgnoredWhenNotSecured) { - rtc::scoped_ptr test(JingleTest()); - rtc::scoped_ptr elem; - test->TestGoodIncomingInitiate( - AddEncryption(kJingleVideoInitiate, kJingleCryptoOffer), - VideoCallOptions(), - elem.use()); -} - -// Offer has crypto required but the session is not secure, fail. -TEST_F(MediaSessionTest, JingleInitiateWithCryptoRequiredWhenNotSecured) { - rtc::scoped_ptr test(JingleTest()); - test->TestBadIncomingInitiate(AddEncryption(kJingleVideoInitiate, - kJingleRequiredCryptoOffer)); -} - -// Offer has no crypto but the session is secure required, fail. -TEST_F(MediaSessionTest, JingleInitiateWithNoCryptoFailsWhenSecureRequired) { - rtc::scoped_ptr test(JingleTest()); - test->ExpectCrypto(cricket::SEC_REQUIRED); - test->TestBadIncomingInitiate(kJingleInitiate); -} - -// Offer has crypto and session is secure, expect crypto in the answer. -TEST_F(MediaSessionTest, JingleInitiateWithCryptoWhenSecureEnabled) { - rtc::scoped_ptr test(JingleTest()); - rtc::scoped_ptr elem; - test->ExpectCrypto(cricket::SEC_ENABLED); - test->TestGoodIncomingInitiate( - AddEncryption(kJingleVideoInitiate, kJingleCryptoOffer), - VideoCallOptions(), - elem.use()); -} - -// Offer has crypto and session is secure required, expect crypto in -// the answer. -TEST_F(MediaSessionTest, JingleInitiateWithCryptoWhenSecureRequired) { - rtc::scoped_ptr test(JingleTest()); - rtc::scoped_ptr elem; - test->ExpectCrypto(cricket::SEC_REQUIRED); - test->TestGoodIncomingInitiate( - AddEncryption(kJingleVideoInitiate, kJingleCryptoOffer), - VideoCallOptions(), - elem.use()); -} - -// Offer has unsupported crypto and session is secure, no crypto in -// the answer. -TEST_F(MediaSessionTest, JingleInitiateWithUnsupportedCrypto) { - rtc::scoped_ptr test(JingleTest()); - rtc::scoped_ptr elem; - test->MakeSignalingSecure(cricket::SEC_ENABLED); - test->TestGoodIncomingInitiate( - AddEncryption(kJingleInitiate, kJingleUnsupportedCryptoOffer), - VideoCallOptions(), - elem.use()); -} - -// Offer has unsupported REQUIRED crypto and session is not secure, fail. -TEST_F(MediaSessionTest, JingleInitiateWithRequiredUnsupportedCrypto) { - rtc::scoped_ptr test(JingleTest()); - test->TestBadIncomingInitiate( - AddEncryption(kJingleInitiate, kJingleRequiredUnsupportedCryptoOffer)); -} - -// Offer has unsupported REQUIRED crypto and session is secure, fail. -TEST_F(MediaSessionTest, - JingleInitiateWithRequiredUnsupportedCryptoWhenSecure) { - rtc::scoped_ptr test(JingleTest()); - test->MakeSignalingSecure(cricket::SEC_ENABLED); - test->TestBadIncomingInitiate( - AddEncryption(kJingleInitiate, kJingleRequiredUnsupportedCryptoOffer)); -} - -// Offer has unsupported REQUIRED crypto and session is required secure, fail. -TEST_F(MediaSessionTest, - JingleInitiateWithRequiredUnsupportedCryptoWhenSecureRequired) { - rtc::scoped_ptr test(JingleTest()); - test->MakeSignalingSecure(cricket::SEC_REQUIRED); - test->TestBadIncomingInitiate( - AddEncryption(kJingleInitiate, kJingleRequiredUnsupportedCryptoOffer)); -} - -TEST_F(MediaSessionTest, JingleGoodOutgoingInitiateWithCrypto) { - rtc::scoped_ptr test(JingleTest()); - test->ExpectCrypto(cricket::SEC_ENABLED); - test->TestGoodOutgoingInitiate(AudioCallOptions()); -} - -TEST_F(MediaSessionTest, JingleGoodOutgoingInitiateWithCryptoRequired) { - rtc::scoped_ptr test(JingleTest()); - test->ExpectCrypto(cricket::SEC_REQUIRED); - test->TestGoodOutgoingInitiate(AudioCallOptions()); -} - -TEST_F(MediaSessionTest, JingleIncomingAcceptWithSsrcs) { - rtc::scoped_ptr test(JingleTest()); - cricket::CallOptions options = VideoCallOptions(); - options.is_muc = true; - test->TestIncomingAcceptWithSsrcs(kJingleAcceptWithSsrcs, options); -} - -TEST_F(MediaSessionTest, JingleIncomingAcceptWithRtpDataSsrcs) { - rtc::scoped_ptr test(JingleTest()); - cricket::CallOptions options = VideoCallOptions(); - options.is_muc = true; - options.data_channel_type = cricket::DCT_RTP; - test->TestIncomingAcceptWithSsrcs(kJingleAcceptWithRtpDataSsrcs, options); -} - -TEST_F(MediaSessionTest, JingleIncomingAcceptWithSctpData) { - rtc::scoped_ptr test(JingleTest()); - cricket::CallOptions options = VideoCallOptions(); - options.is_muc = true; - options.data_channel_type = cricket::DCT_SCTP; - test->TestIncomingAcceptWithSsrcs(kJingleAcceptWithSctpData, options); -} - -TEST_F(MediaSessionTest, JingleStreamsUpdateAndView) { - rtc::scoped_ptr test(JingleTest()); - test->TestStreamsUpdateAndViewRequests(); -} - -TEST_F(MediaSessionTest, JingleSendVideoStreamUpdate) { - rtc::scoped_ptr test(JingleTest()); - test->TestSendVideoStreamUpdate(); -} - -// Gingle tests - -TEST_F(MediaSessionTest, GingleGoodVideoInitiate) { - rtc::scoped_ptr elem; - rtc::scoped_ptr test(GingleTest()); - test->TestGoodIncomingInitiate( - kGingleVideoInitiate, VideoCallOptions(), elem.use()); - test->TestCodecsOfVideoInitiate(elem.get()); -} - -TEST_F(MediaSessionTest, GingleGoodVideoInitiateWithBandwidth) { - rtc::scoped_ptr elem; - rtc::scoped_ptr test(GingleTest()); - test->ExpectVideoBandwidth(42000); - test->TestGoodIncomingInitiate( - kGingleVideoInitiateWithBandwidth, VideoCallOptions(), elem.use()); -} - -TEST_F(MediaSessionTest, GingleGoodInitiateAllSupportedAudioCodecs) { - rtc::scoped_ptr elem; - rtc::scoped_ptr test(GingleTest()); - test->TestGoodIncomingInitiate( - kGingleInitiate, AudioCallOptions(), elem.use()); - test->TestHasAllSupportedAudioCodecs(elem.get()); -} - -TEST_F(MediaSessionTest, GingleGoodInitiateAllSupportedAudioCodecsWithCrypto) { - rtc::scoped_ptr elem; - rtc::scoped_ptr test(GingleTest()); - test->ExpectCrypto(cricket::SEC_ENABLED); - test->TestGoodIncomingInitiate( - AddEncryption(kGingleInitiate, kGingleCryptoOffer), - AudioCallOptions(), - elem.use()); - test->TestHasAllSupportedAudioCodecs(elem.get()); -} - -// Changes the codecs that our FakeMediaEngine will support with a different -// preference order than the incoming offer. -// Verifies the answer accepts the preference order of the remote peer. -TEST_F(MediaSessionTest, GingleGoodInitiateDifferentPreferenceAudioCodecs) { - rtc::scoped_ptr test(GingleTest()); - test->fme()->SetAudioCodecs(MAKE_VECTOR(kAudioCodecsDifferentPreference)); - rtc::scoped_ptr elem; - test->TestGoodIncomingInitiate( - kGingleInitiate, AudioCallOptions(), elem.use()); - test->TestHasAllSupportedAudioCodecs(elem.get()); -} - -TEST_F(MediaSessionTest, GingleGoodInitiateSomeUnsupportedAudioCodecs) { - rtc::scoped_ptr elem; - rtc::scoped_ptr test(GingleTest()); - test->TestGoodIncomingInitiate( - kGingleInitiateSomeUnsupported, AudioCallOptions(), elem.use()); - test->TestHasAudioCodecsFromInitiateSomeUnsupported(elem.get()); -} - -TEST_F(MediaSessionTest, GingleGoodInitiateDynamicAudioCodecs) { - rtc::scoped_ptr elem; - rtc::scoped_ptr test(GingleTest()); - test->TestGoodIncomingInitiate( - kGingleInitiateDynamicAudioCodecs, AudioCallOptions(), elem.use()); - test->TestHasAudioCodecsFromInitiateDynamicAudioCodecs(elem.get()); -} - -TEST_F(MediaSessionTest, GingleGoodInitiateStaticAudioCodecs) { - rtc::scoped_ptr elem; - rtc::scoped_ptr test(GingleTest()); - test->TestGoodIncomingInitiate( - kGingleInitiateStaticAudioCodecs, AudioCallOptions(), elem.use()); - test->TestHasAudioCodecsFromInitiateStaticAudioCodecs(elem.get()); -} - -TEST_F(MediaSessionTest, GingleGoodInitiateNoAudioCodecs) { - rtc::scoped_ptr elem; - rtc::scoped_ptr test(GingleTest()); - test->TestGoodIncomingInitiate( - kGingleInitiateNoAudioCodecs, AudioCallOptions(), elem.use()); - test->TestHasDefaultAudioCodecs(elem.get()); -} - -TEST_F(MediaSessionTest, GingleBadInitiateNoSupportedAudioCodecs) { - rtc::scoped_ptr test(GingleTest()); - test->TestBadIncomingInitiate(kGingleInitiateNoSupportedAudioCodecs); -} - -TEST_F(MediaSessionTest, GingleBadInitiateWrongClockrates) { - rtc::scoped_ptr test(GingleTest()); - test->TestBadIncomingInitiate(kGingleInitiateWrongClockrates); -} - -TEST_F(MediaSessionTest, GingleBadInitiateWrongChannels) { - rtc::scoped_ptr test(GingleTest()); - test->TestBadIncomingInitiate(kGingleInitiateWrongChannels); -} - -TEST_F(MediaSessionTest, GingleBadInitiateNoPayloadTypes) { - rtc::scoped_ptr test(GingleTest()); - test->TestBadIncomingInitiate(kGingleInitiateNoPayloadTypes); -} - -TEST_F(MediaSessionTest, GingleBadInitiateDynamicWithoutNames) { - rtc::scoped_ptr test(GingleTest()); - test->TestBadIncomingInitiate(kGingleInitiateDynamicWithoutNames); -} - -TEST_F(MediaSessionTest, GingleGoodOutgoingInitiate) { - rtc::scoped_ptr test(GingleTest()); - test->TestGoodOutgoingInitiate(AudioCallOptions()); -} - -TEST_F(MediaSessionTest, GingleGoodOutgoingInitiateWithBandwidth) { - rtc::scoped_ptr test(GingleTest()); - cricket::CallOptions options = VideoCallOptions(); - options.video_bandwidth = 42000; - test->TestGoodOutgoingInitiate(options); -} - -// Crypto related tests. - -// Offer has crypto but the session is not secured, just ignore it. -TEST_F(MediaSessionTest, GingleInitiateWithCryptoIsIgnoredWhenNotSecured) { - rtc::scoped_ptr elem; - rtc::scoped_ptr test(GingleTest()); - test->TestGoodIncomingInitiate( - AddEncryption(kGingleInitiate, kGingleCryptoOffer), - VideoCallOptions(), - elem.use()); -} - -// Offer has crypto required but the session is not secure, fail. -TEST_F(MediaSessionTest, GingleInitiateWithCryptoRequiredWhenNotSecured) { - rtc::scoped_ptr test(GingleTest()); - test->TestBadIncomingInitiate(AddEncryption(kGingleInitiate, - kGingleRequiredCryptoOffer)); -} - -// Offer has no crypto but the session is secure required, fail. -TEST_F(MediaSessionTest, GingleInitiateWithNoCryptoFailsWhenSecureRequired) { - rtc::scoped_ptr test(GingleTest()); - test->ExpectCrypto(cricket::SEC_REQUIRED); - test->TestBadIncomingInitiate(kGingleInitiate); -} - -// Offer has crypto and session is secure, expect crypto in the answer. -TEST_F(MediaSessionTest, GingleInitiateWithCryptoWhenSecureEnabled) { - rtc::scoped_ptr elem; - rtc::scoped_ptr test(GingleTest()); - test->ExpectCrypto(cricket::SEC_ENABLED); - test->TestGoodIncomingInitiate( - AddEncryption(kGingleInitiate, kGingleCryptoOffer), - VideoCallOptions(), - elem.use()); -} - -// Offer has crypto and session is secure required, expect crypto in -// the answer. -TEST_F(MediaSessionTest, GingleInitiateWithCryptoWhenSecureRequired) { - rtc::scoped_ptr elem; - rtc::scoped_ptr test(GingleTest()); - test->ExpectCrypto(cricket::SEC_REQUIRED); - test->TestGoodIncomingInitiate( - AddEncryption(kGingleInitiate, kGingleCryptoOffer), - VideoCallOptions(), - elem.use()); -} - -// Offer has unsupported crypto and session is secure, no crypto in -// the answer. -TEST_F(MediaSessionTest, GingleInitiateWithUnsupportedCrypto) { - rtc::scoped_ptr elem; - rtc::scoped_ptr test(GingleTest()); - test->MakeSignalingSecure(cricket::SEC_ENABLED); - test->TestGoodIncomingInitiate( - AddEncryption(kGingleInitiate, kGingleUnsupportedCryptoOffer), - VideoCallOptions(), - elem.use()); -} - -// Offer has unsupported REQUIRED crypto and session is not secure, fail. -TEST_F(MediaSessionTest, GingleInitiateWithRequiredUnsupportedCrypto) { - rtc::scoped_ptr test(GingleTest()); - test->TestBadIncomingInitiate( - AddEncryption(kGingleInitiate, kGingleRequiredUnsupportedCryptoOffer)); -} - -// Offer has unsupported REQUIRED crypto and session is secure, fail. -TEST_F(MediaSessionTest, - GingleInitiateWithRequiredUnsupportedCryptoWhenSecure) { - rtc::scoped_ptr test(GingleTest()); - test->MakeSignalingSecure(cricket::SEC_ENABLED); - test->TestBadIncomingInitiate( - AddEncryption(kGingleInitiate, kGingleRequiredUnsupportedCryptoOffer)); -} - -// Offer has unsupported REQUIRED crypto and session is required secure, fail. -TEST_F(MediaSessionTest, - GingleInitiateWithRequiredUnsupportedCryptoWhenSecureRequired) { - rtc::scoped_ptr test(GingleTest()); - test->MakeSignalingSecure(cricket::SEC_REQUIRED); - test->TestBadIncomingInitiate( - AddEncryption(kGingleInitiate, kGingleRequiredUnsupportedCryptoOffer)); -} - -TEST_F(MediaSessionTest, GingleGoodOutgoingInitiateWithCrypto) { - rtc::scoped_ptr test(GingleTest()); - test->ExpectCrypto(cricket::SEC_ENABLED); - test->TestGoodOutgoingInitiate(AudioCallOptions()); -} - -TEST_F(MediaSessionTest, GingleGoodOutgoingInitiateWithCryptoRequired) { - rtc::scoped_ptr test(GingleTest()); - test->ExpectCrypto(cricket::SEC_REQUIRED); - test->TestGoodOutgoingInitiate(AudioCallOptions()); -} - -TEST_F(MediaSessionTest, GingleIncomingAcceptWithSsrcs) { - rtc::scoped_ptr test(GingleTest()); - cricket::CallOptions options = VideoCallOptions(); - options.is_muc = true; - test->TestIncomingAcceptWithSsrcs(kGingleAcceptWithSsrcs, options); -} - -TEST_F(MediaSessionTest, GingleGoodOutgoingInitiateWithRtpData) { - rtc::scoped_ptr test(GingleTest()); - cricket::CallOptions options; - options.data_channel_type = cricket::DCT_RTP; - test->ExpectCrypto(cricket::SEC_ENABLED); - test->TestGoodOutgoingInitiate(options); -} diff --git a/webrtc/libjingle/session/p2ptransportparser.cc b/webrtc/libjingle/session/p2ptransportparser.cc deleted file mode 100644 index cb3467148..000000000 --- a/webrtc/libjingle/session/p2ptransportparser.cc +++ /dev/null @@ -1,216 +0,0 @@ -/* - * Copyright 2004 The WebRTC Project Authors. All rights reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#include "webrtc/libjingle/session/p2ptransportparser.h" - -#include - -#include "webrtc/p2p/base/constants.h" -#include "webrtc/libjingle/session/constants.h" -#include "webrtc/libjingle/session/parsing.h" -#include "webrtc/libjingle/session/sessionmanager.h" -#include "webrtc/libjingle/session/sessionmessages.h" -#include "webrtc/libjingle/xmllite/qname.h" -#include "webrtc/libjingle/xmllite/xmlelement.h" -#include "webrtc/libjingle/xmpp/constants.h" -#include "webrtc/base/base64.h" -#include "webrtc/base/common.h" -#include "webrtc/base/stringencode.h" -#include "webrtc/base/stringutils.h" - -namespace cricket { - -static buzz::XmlElement* NewTransportElement(const std::string& name) { - return new buzz::XmlElement(buzz::QName(name, LN_TRANSPORT), true); -} - -bool P2PTransportParser::ParseTransportDescription( - const buzz::XmlElement* elem, - const CandidateTranslator* translator, - TransportDescription* desc, - ParseError* error) { - ASSERT(elem->Name().LocalPart() == LN_TRANSPORT); - desc->transport_type = elem->Name().Namespace(); - if (desc->transport_type != NS_GINGLE_P2P) - return BadParse("Unsupported transport type", error); - - for (const buzz::XmlElement* candidate_elem = elem->FirstElement(); - candidate_elem != NULL; - candidate_elem = candidate_elem->NextElement()) { - // Only look at local part because the namespace might (eventually) - // be NS_GINGLE_P2P or NS_JINGLE_ICE_UDP. - if (candidate_elem->Name().LocalPart() == LN_CANDIDATE) { - Candidate candidate; - if (!ParseCandidate(ICEPROTO_GOOGLE, candidate_elem, translator, - &candidate, error)) { - return false; - } - - desc->candidates.push_back(candidate); - } - } - return true; -} - -bool P2PTransportParser::WriteTransportDescription( - const TransportDescription& desc, - const CandidateTranslator* translator, - buzz::XmlElement** out_elem, - WriteError* error) { - TransportProtocol proto = TransportProtocolFromDescription(&desc); - rtc::scoped_ptr trans_elem( - NewTransportElement(desc.transport_type)); - - // Fail if we get HYBRID or ICE right now. - // TODO(juberti): Add ICE and HYBRID serialization. - if (proto != ICEPROTO_GOOGLE) { - LOG(LS_ERROR) << "Failed to serialize non-GICE TransportDescription"; - return false; - } - - for (std::vector::const_iterator iter = desc.candidates.begin(); - iter != desc.candidates.end(); ++iter) { - rtc::scoped_ptr cand_elem( - new buzz::XmlElement(QN_GINGLE_P2P_CANDIDATE)); - if (!WriteCandidate(proto, *iter, translator, cand_elem.get(), error)) { - return false; - } - trans_elem->AddElement(cand_elem.release()); - } - - *out_elem = trans_elem.release(); - return true; -} - -bool P2PTransportParser::ParseGingleCandidate( - const buzz::XmlElement* elem, - const CandidateTranslator* translator, - Candidate* candidate, - ParseError* error) { - return ParseCandidate(ICEPROTO_GOOGLE, elem, translator, candidate, error); -} - -bool P2PTransportParser::WriteGingleCandidate( - const Candidate& candidate, - const CandidateTranslator* translator, - buzz::XmlElement** out_elem, - WriteError* error) { - rtc::scoped_ptr elem( - new buzz::XmlElement(QN_GINGLE_CANDIDATE)); - bool ret = WriteCandidate(ICEPROTO_GOOGLE, candidate, translator, elem.get(), - error); - if (ret) { - *out_elem = elem.release(); - } - return ret; -} - -bool P2PTransportParser::VerifyUsernameFormat(TransportProtocol proto, - const std::string& username, - ParseError* error) { - if (proto == ICEPROTO_GOOGLE || proto == ICEPROTO_HYBRID) { - if (username.size() > GICE_UFRAG_MAX_LENGTH) - return BadParse("candidate username is too long", error); - if (!rtc::Base64::IsBase64Encoded(username)) - return BadParse("candidate username has non-base64 encoded characters", - error); - } else if (proto == ICEPROTO_RFC5245) { - if (username.size() > ICE_UFRAG_MAX_LENGTH) - return BadParse("candidate username is too long", error); - } - return true; -} - -bool P2PTransportParser::ParseCandidate(TransportProtocol proto, - const buzz::XmlElement* elem, - const CandidateTranslator* translator, - Candidate* candidate, - ParseError* error) { - ASSERT(proto == ICEPROTO_GOOGLE); - ASSERT(translator != NULL); - - if (!elem->HasAttr(buzz::QN_NAME) || - !elem->HasAttr(QN_ADDRESS) || - !elem->HasAttr(QN_PORT) || - !elem->HasAttr(QN_USERNAME) || - !elem->HasAttr(QN_PROTOCOL) || - !elem->HasAttr(QN_GENERATION)) { - return BadParse("candidate missing required attribute", error); - } - - rtc::SocketAddress address; - if (!ParseAddress(elem, QN_ADDRESS, QN_PORT, &address, error)) - return false; - - std::string channel_name = elem->Attr(buzz::QN_NAME); - int component = 0; - if (!translator || - !translator->GetComponentFromChannelName(channel_name, &component)) { - return BadParse("candidate has unknown channel name " + channel_name, - error); - } - - float preference = 0.0; - if (!GetXmlAttr(elem, QN_PREFERENCE, 0.0f, &preference)) { - return BadParse("candidate has unknown preference", error); - } - - candidate->set_component(component); - candidate->set_address(address); - candidate->set_username(elem->Attr(QN_USERNAME)); - candidate->set_preference(preference); - candidate->set_protocol(elem->Attr(QN_PROTOCOL)); - candidate->set_generation_str(elem->Attr(QN_GENERATION)); - if (elem->HasAttr(QN_PASSWORD)) - candidate->set_password(elem->Attr(QN_PASSWORD)); - if (elem->HasAttr(buzz::QN_TYPE)) - candidate->set_type(elem->Attr(buzz::QN_TYPE)); - if (elem->HasAttr(QN_NETWORK)) - candidate->set_network_name(elem->Attr(QN_NETWORK)); - - if (!VerifyUsernameFormat(proto, candidate->username(), error)) - return false; - - return true; -} - -bool P2PTransportParser::WriteCandidate(TransportProtocol proto, - const Candidate& candidate, - const CandidateTranslator* translator, - buzz::XmlElement* elem, - WriteError* error) { - ASSERT(proto == ICEPROTO_GOOGLE); - ASSERT(translator != NULL); - - std::string channel_name; - if (!translator || - !translator->GetChannelNameFromComponent( - candidate.component(), &channel_name)) { - return BadWrite("Cannot write candidate because of unknown component.", - error); - } - - elem->SetAttr(buzz::QN_NAME, channel_name); - elem->SetAttr(QN_ADDRESS, candidate.address().ipaddr().ToString()); - elem->SetAttr(QN_PORT, candidate.address().PortAsString()); - AddXmlAttr(elem, QN_PREFERENCE, candidate.preference()); - elem->SetAttr(QN_USERNAME, candidate.username()); - elem->SetAttr(QN_PROTOCOL, candidate.protocol()); - elem->SetAttr(QN_GENERATION, candidate.generation_str()); - if (!candidate.password().empty()) - elem->SetAttr(QN_PASSWORD, candidate.password()); - elem->SetAttr(buzz::QN_TYPE, candidate.type()); - if (!candidate.network_name().empty()) - elem->SetAttr(QN_NETWORK, candidate.network_name()); - - return true; -} - -} // namespace cricket diff --git a/webrtc/libjingle/session/p2ptransportparser.h b/webrtc/libjingle/session/p2ptransportparser.h deleted file mode 100644 index fd6fdeb0b..000000000 --- a/webrtc/libjingle/session/p2ptransportparser.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright 2004 The WebRTC Project Authors. All rights reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#ifndef WEBRTC_LIBJINGLE_SESSION_P2PTRANSPORTPARSER_H_ -#define WEBRTC_LIBJINGLE_SESSION_P2PTRANSPORTPARSER_H_ - -#include -#include "webrtc/libjingle/session/transportparser.h" - -namespace cricket { - -class P2PTransportParser : public TransportParser { - public: - P2PTransportParser() {} - // Translator may be null, in which case ParseCandidates should - // return false if there are candidates to parse. We can't not call - // ParseCandidates because there's no way to know ahead of time if - // there are candidates or not. - - // Jingle-specific functions; can be used with either ICE, GICE, or HYBRID. - virtual bool ParseTransportDescription(const buzz::XmlElement* elem, - const CandidateTranslator* translator, - TransportDescription* desc, - ParseError* error); - virtual bool WriteTransportDescription(const TransportDescription& desc, - const CandidateTranslator* translator, - buzz::XmlElement** elem, - WriteError* error); - - // Legacy Gingle functions; only can be used with GICE. - virtual bool ParseGingleCandidate(const buzz::XmlElement* elem, - const CandidateTranslator* translator, - Candidate* candidate, - ParseError* error); - virtual bool WriteGingleCandidate(const Candidate& candidate, - const CandidateTranslator* translator, - buzz::XmlElement** elem, - WriteError* error); - - private: - bool ParseCandidate(TransportProtocol proto, - const buzz::XmlElement* elem, - const CandidateTranslator* translator, - Candidate* candidate, - ParseError* error); - bool WriteCandidate(TransportProtocol proto, - const Candidate& candidate, - const CandidateTranslator* translator, - buzz::XmlElement* elem, - WriteError* error); - bool VerifyUsernameFormat(TransportProtocol proto, - const std::string& username, - ParseError* error); - - DISALLOW_COPY_AND_ASSIGN(P2PTransportParser); -}; - -} // namespace cricket - -#endif // WEBRTC_LIBJINGLE_SESSION_P2PTRANSPORTPARSER_H_ diff --git a/webrtc/libjingle/session/parsing.cc b/webrtc/libjingle/session/parsing.cc deleted file mode 100644 index 9a6100aad..000000000 --- a/webrtc/libjingle/session/parsing.cc +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright 2010 The WebRTC Project Authors. All rights reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#include "webrtc/libjingle/session/parsing.h" - -#include -#include -#include "webrtc/base/stringutils.h" - -namespace { -static const char kTrue[] = "true"; -static const char kOne[] = "1"; -} - -namespace cricket { - -bool BadParse(const std::string& text, ParseError* err) { - if (err != NULL) { - err->text = text; - } - return false; -} - -bool BadWrite(const std::string& text, WriteError* err) { - if (err != NULL) { - err->text = text; - } - return false; -} - -std::string GetXmlAttr(const buzz::XmlElement* elem, - const buzz::QName& name, - const std::string& def) { - std::string val = elem->Attr(name); - return val.empty() ? def : val; -} - -std::string GetXmlAttr(const buzz::XmlElement* elem, - const buzz::QName& name, - const char* def) { - return GetXmlAttr(elem, name, std::string(def)); -} - -bool GetXmlAttr(const buzz::XmlElement* elem, - const buzz::QName& name, bool def) { - std::string val = elem->Attr(name); - std::transform(val.begin(), val.end(), val.begin(), tolower); - - return val.empty() ? def : (val == kTrue || val == kOne); -} - -int GetXmlAttr(const buzz::XmlElement* elem, - const buzz::QName& name, int def) { - std::string val = elem->Attr(name); - return val.empty() ? def : atoi(val.c_str()); -} - -const buzz::XmlElement* GetXmlChild(const buzz::XmlElement* parent, - const std::string& name) { - for (const buzz::XmlElement* child = parent->FirstElement(); - child != NULL; - child = child->NextElement()) { - if (child->Name().LocalPart() == name) { - return child; - } - } - return NULL; -} - -bool RequireXmlChild(const buzz::XmlElement* parent, - const std::string& name, - const buzz::XmlElement** child, - ParseError* error) { - *child = GetXmlChild(parent, name); - if (*child == NULL) { - return BadParse("element '" + parent->Name().Merged() + - "' missing required child '" + name, - error); - } else { - return true; - } -} - -bool RequireXmlAttr(const buzz::XmlElement* elem, - const buzz::QName& name, - std::string* value, - ParseError* error) { - if (!elem->HasAttr(name)) { - return BadParse("element '" + elem->Name().Merged() + - "' missing required attribute '" - + name.Merged() + "'", - error); - } else { - *value = elem->Attr(name); - return true; - } -} - -void AddXmlAttrIfNonEmpty(buzz::XmlElement* elem, - const buzz::QName name, - const std::string& value) { - if (!value.empty()) { - elem->AddAttr(name, value); - } -} - -void AddXmlChildren(buzz::XmlElement* parent, - const std::vector& children) { - for (std::vector::const_iterator iter = children.begin(); - iter != children.end(); - iter++) { - parent->AddElement(*iter); - } -} - -void CopyXmlChildren(const buzz::XmlElement* source, buzz::XmlElement* dest) { - for (const buzz::XmlElement* child = source->FirstElement(); - child != NULL; - child = child->NextElement()) { - dest->AddElement(new buzz::XmlElement(*child)); - } -} - -std::vector CopyOfXmlChildren(const buzz::XmlElement* elem) { - std::vector children; - for (const buzz::XmlElement* child = elem->FirstElement(); - child != NULL; - child = child->NextElement()) { - children.push_back(new buzz::XmlElement(*child)); - } - return children; -} - -} // namespace cricket diff --git a/webrtc/libjingle/session/parsing.h b/webrtc/libjingle/session/parsing.h deleted file mode 100644 index 1d1b69d08..000000000 --- a/webrtc/libjingle/session/parsing.h +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright 2010 The WebRTC Project Authors. All rights reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#ifndef WEBRTC_LIBJINGLE_SESSION_PARSING_H_ -#define WEBRTC_LIBJINGLE_SESSION_PARSING_H_ - -#include -#include -#include "webrtc/libjingle/xmllite/xmlelement.h" // Needed to delete ParseError.extra. -#include "webrtc/base/basictypes.h" -#include "webrtc/base/stringencode.h" - -namespace cricket { - -typedef std::vector XmlElements; - -// We decided "bool Parse(in, out*, error*)" is generally the best -// parse signature. "out Parse(in)" doesn't allow for errors. -// "error* Parse(in, out*)" doesn't allow flexible memory management. - -// The error type for parsing. -struct ParseError { - public: - // explains the error - std::string text; - // provide details about what wasn't parsable - const buzz::XmlElement* extra; - - ParseError() : extra(NULL) {} - - ~ParseError() { - delete extra; - } - - void SetText(const std::string& text) { - this->text = text; - } -}; - -// The error type for writing. -struct WriteError { - std::string text; - - void SetText(const std::string& text) { - this->text = text; - } -}; - -// Convenience method for returning a message when parsing fails. -bool BadParse(const std::string& text, ParseError* err); - -// Convenience method for returning a message when writing fails. -bool BadWrite(const std::string& text, WriteError* error); - -// helper XML functions -std::string GetXmlAttr(const buzz::XmlElement* elem, - const buzz::QName& name, - const std::string& def); -std::string GetXmlAttr(const buzz::XmlElement* elem, - const buzz::QName& name, - const char* def); -// Return true if the value is "true" or "1". -bool GetXmlAttr(const buzz::XmlElement* elem, - const buzz::QName& name, bool def); -int GetXmlAttr(const buzz::XmlElement* elem, - const buzz::QName& name, int def); - -template -bool GetXmlAttr(const buzz::XmlElement* elem, - const buzz::QName& name, - T* val_out) { - if (!elem->HasAttr(name)) { - return false; - } - std::string unparsed = elem->Attr(name); - return rtc::FromString(unparsed, val_out); -} - -template -bool GetXmlAttr(const buzz::XmlElement* elem, - const buzz::QName& name, - const T& def, - T* val_out) { - if (!elem->HasAttr(name)) { - *val_out = def; - return true; - } - return GetXmlAttr(elem, name, val_out); -} - -template -bool AddXmlAttr(buzz::XmlElement* elem, - const buzz::QName& name, const T& val) { - std::string buf; - if (!rtc::ToString(val, &buf)) { - return false; - } - elem->AddAttr(name, buf); - return true; -} - -template -bool SetXmlBody(buzz::XmlElement* elem, const T& val) { - std::string buf; - if (!rtc::ToString(val, &buf)) { - return false; - } - elem->SetBodyText(buf); - return true; -} - -const buzz::XmlElement* GetXmlChild(const buzz::XmlElement* parent, - const std::string& name); - -bool RequireXmlChild(const buzz::XmlElement* parent, - const std::string& name, - const buzz::XmlElement** child, - ParseError* error); -bool RequireXmlAttr(const buzz::XmlElement* elem, - const buzz::QName& name, - std::string* value, - ParseError* error); -void AddXmlAttrIfNonEmpty(buzz::XmlElement* elem, - const buzz::QName name, - const std::string& value); -void AddXmlChildren(buzz::XmlElement* parent, - const std::vector& children); -void CopyXmlChildren(const buzz::XmlElement* source, buzz::XmlElement* dest); -std::vector CopyOfXmlChildren(const buzz::XmlElement* elem); - -} // namespace cricket - -#endif // WEBRTC_LIBJINGLE_SESSION_PARSING_H_ diff --git a/webrtc/libjingle/session/rawtransportparser.cc b/webrtc/libjingle/session/rawtransportparser.cc deleted file mode 100644 index e8df956a0..000000000 --- a/webrtc/libjingle/session/rawtransportparser.cc +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright 2004 The WebRTC Project Authors. All rights reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#include "webrtc/libjingle/session/rawtransportparser.h" - -#include -#include - -#include "webrtc/libjingle/session/parsing.h" -#include "webrtc/libjingle/xmllite/qname.h" -#include "webrtc/libjingle/xmllite/xmlelement.h" -#include "webrtc/libjingle/xmpp/constants.h" -#include "webrtc/p2p/base/constants.h" - -#if defined(FEATURE_ENABLE_PSTN) -namespace cricket { - -bool RawTransportParser::ParseCandidates(SignalingProtocol protocol, - const buzz::XmlElement* elem, - const CandidateTranslator* translator, - Candidates* candidates, - ParseError* error) { - for (const buzz::XmlElement* cand_elem = elem->FirstElement(); - cand_elem != NULL; - cand_elem = cand_elem->NextElement()) { - if (cand_elem->Name() == QN_GINGLE_RAW_CHANNEL) { - if (!cand_elem->HasAttr(buzz::QN_NAME)) { - return BadParse("no channel name given", error); - } - if (NS_GINGLE_RAW != cand_elem->Attr(buzz::QN_NAME)) { - return BadParse("channel named does not exist", error); - } - rtc::SocketAddress addr; - if (!ParseRawAddress(cand_elem, &addr, error)) - return false; - - Candidate candidate; - candidate.set_component(1); - candidate.set_address(addr); - candidates->push_back(candidate); - } - } - return true; -} - -bool RawTransportParser::WriteCandidates(SignalingProtocol protocol, - const Candidates& candidates, - const CandidateTranslator* translator, - XmlElements* candidate_elems, - WriteError* error) { - for (std::vector::const_iterator - cand = candidates.begin(); - cand != candidates.end(); - ++cand) { - ASSERT(cand->component() == 1); - ASSERT(cand->protocol() == "udp"); - rtc::SocketAddress addr = cand->address(); - - buzz::XmlElement* elem = new buzz::XmlElement(QN_GINGLE_RAW_CHANNEL); - elem->SetAttr(buzz::QN_NAME, NS_GINGLE_RAW); - elem->SetAttr(QN_ADDRESS, addr.ipaddr().ToString()); - elem->SetAttr(QN_PORT, addr.PortAsString()); - candidate_elems->push_back(elem); - } - return true; -} - -bool RawTransportParser::ParseRawAddress(const buzz::XmlElement* elem, - rtc::SocketAddress* addr, - ParseError* error) { - // Make sure the required attributes exist - if (!elem->HasAttr(QN_ADDRESS) || - !elem->HasAttr(QN_PORT)) { - return BadParse("channel missing required attribute", error); - } - - // Parse the address. - if (!ParseAddress(elem, QN_ADDRESS, QN_PORT, addr, error)) - return false; - - return true; -} - -} // namespace cricket -#endif // defined(FEATURE_ENABLE_PSTN) diff --git a/webrtc/libjingle/session/rawtransportparser.h b/webrtc/libjingle/session/rawtransportparser.h deleted file mode 100644 index 7dff9fec6..000000000 --- a/webrtc/libjingle/session/rawtransportparser.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2004 The WebRTC Project Authors. All rights reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#ifndef WEBRTC_LIBJINGLE_SESSION_RAWTRANSPORTPARSER_H_ -#define WEBRTC_LIBJINGLE_SESSION_RAWTRANSPORTPARSER_H_ - -#include - -#include "webrtc/p2p/base/constants.h" -#include "webrtc/libjingle/session/constants.h" -#include "webrtc/libjingle/session/transportparser.h" - -namespace cricket { - -class RawTransportParser : public TransportParser { - public: - RawTransportParser() {} - - virtual bool ParseCandidates(SignalingProtocol protocol, - const buzz::XmlElement* elem, - const CandidateTranslator* translator, - Candidates* candidates, - ParseError* error); - virtual bool WriteCandidates(SignalingProtocol protocol, - const Candidates& candidates, - const CandidateTranslator* translator, - XmlElements* candidate_elems, - WriteError* error); - private: - // Parses the given element, which should describe the address to use for a - // given channel. This will return false and signal an error if the address - // or channel name is bad. - bool ParseRawAddress(const buzz::XmlElement* elem, - rtc::SocketAddress* addr, - ParseError* error); - - DISALLOW_COPY_AND_ASSIGN(RawTransportParser); -}; - -} // namespace cricket - -#endif // WEBRTC_LIBJINGLE_SESSION_RAWTRANSPORTPARSER_H_ diff --git a/webrtc/libjingle/session/session_unittest.cc b/webrtc/libjingle/session/session_unittest.cc deleted file mode 100644 index e1168db26..000000000 --- a/webrtc/libjingle/session/session_unittest.cc +++ /dev/null @@ -1,2430 +0,0 @@ -/* - * Copyright 2004 The WebRTC Project Authors. All rights reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#include - -#include -#include -#include - -#include "webrtc/base/base64.h" -#include "webrtc/base/common.h" -#include "webrtc/base/gunit.h" -#include "webrtc/base/helpers.h" -#include "webrtc/base/logging.h" -#include "webrtc/base/natserver.h" -#include "webrtc/base/natsocketfactory.h" -#include "webrtc/base/stringencode.h" -#include "webrtc/libjingle/session/parsing.h" -#include "webrtc/libjingle/session/sessionclient.h" -#include "webrtc/libjingle/session/sessionmanager.h" -#include "webrtc/libjingle/xmpp/constants.h" -#include "webrtc/p2p/base/basicpacketsocketfactory.h" -#include "webrtc/p2p/base/constants.h" -#include "webrtc/p2p/base/p2ptransport.h" -#include "webrtc/p2p/base/portallocator.h" -#include "webrtc/p2p/base/relayport.h" -#include "webrtc/p2p/base/relayserver.h" -#include "webrtc/p2p/base/stunport.h" -#include "webrtc/p2p/base/stunserver.h" -#include "webrtc/p2p/base/transportchannel.h" -#include "webrtc/p2p/base/transportchannelproxy.h" -#include "webrtc/p2p/base/udpport.h" - -using cricket::SignalingProtocol; -using cricket::PROTOCOL_HYBRID; -using cricket::PROTOCOL_JINGLE; -using cricket::PROTOCOL_GINGLE; - -static const std::string kInitiator = "init@init.com"; -static const std::string kResponder = "resp@resp.com"; -// Expected from test random number generator. -static const std::string kSessionId = "9254631414740579489"; -// TODO: When we need to test more than one transport type, -// allow this to be injected like the content types are. -static const std::string kTransportType = "http://www.google.com/transport/p2p"; - -// Controls how long we wait for a session to send messages that we -// expect, in milliseconds. We put it high to avoid flaky tests. -static const int kEventTimeout = 5000; - -static const int kNumPorts = 2; -static const int kPort0 = 28653; -static const int kPortStep = 5; - -int GetPort(int port_index) { - return kPort0 + (port_index * kPortStep); -} - -std::string GetPortString(int port_index) { - return rtc::ToString(GetPort(port_index)); -} - -// Only works for port_index < 10, which is fine for our purposes. -std::string GetUsername(int port_index) { - return "username" + std::string(8, rtc::ToString(port_index)[0]); -} - -// Only works for port_index < 10, which is fine for our purposes. -std::string GetPassword(int port_index) { - return "password" + std::string(8, rtc::ToString(port_index)[0]); -} - -std::string IqAck(const std::string& id, - const std::string& from, - const std::string& to) { - return ""; -} - -std::string IqSet(const std::string& id, - const std::string& from, - const std::string& to, - const std::string& content) { - return "" - + content + - ""; -} - -std::string IqError(const std::string& id, - const std::string& from, - const std::string& to, - const std::string& content) { - return "" - + content + - ""; -} - -std::string GingleSessionXml(const std::string& type, - const std::string& content) { - return "" - + content + - ""; -} - -std::string GingleDescriptionXml(const std::string& content_type) { - return ""; -} - -std::string P2pCandidateXml(const std::string& name, int port_index) { - // Port will update the rtcp username by +1 on the last character. So we need - // to compensate here. See Port::username_fragment() for detail. - std::string username = GetUsername(port_index); - // TODO: Use the component id instead of the channel name to - // determinte if we need to covert the username here. - if (name == "rtcp" || name == "video_rtcp" || name == "chanb") { - char next_ch = username[username.size() - 1]; - ASSERT(username.size() > 0); - rtc::Base64::GetNextBase64Char(next_ch, &next_ch); - username[username.size() - 1] = next_ch; - } - return ""; -} - -std::string JingleActionXml(const std::string& action, - const std::string& content) { - return "" - + content + - ""; -} - -std::string JingleInitiateActionXml(const std::string& content) { - return "" - + content + - ""; -} - -std::string JingleGroupInfoXml(const std::string& content_name_a, - const std::string& content_name_b) { - std::string group_info = ""; - if (!content_name_a.empty()) - group_info += ""; - if (!content_name_b.empty()) - group_info += ""; - group_info += ""; - return group_info; -} - - -std::string JingleEmptyContentXml(const std::string& content_name, - const std::string& content_type, - const std::string& transport_type) { - return "" - "" - "" - ""; -} - -std::string JingleContentXml(const std::string& content_name, - const std::string& content_type, - const std::string& transport_type, - const std::string& transport_main) { - std::string transport = transport_type.empty() ? "" : - "" - + transport_main + - ""; - - return"" - "" - + transport + - ""; -} - -std::string JingleTransportContentXml(const std::string& content_name, - const std::string& transport_type, - const std::string& content) { - return "" - "" - + content + - "" - ""; -} - -std::string GingleInitiateXml(const std::string& content_type) { - return GingleSessionXml( - "initiate", - GingleDescriptionXml(content_type)); -} - -std::string JingleInitiateXml(const std::string& content_name_a, - const std::string& content_type_a, - const std::string& content_name_b, - const std::string& content_type_b, - bool bundle = false) { - std::string content_xml; - if (content_name_b.empty()) { - content_xml = JingleEmptyContentXml( - content_name_a, content_type_a, kTransportType); - } else { - content_xml = JingleEmptyContentXml( - content_name_a, content_type_a, kTransportType) + - JingleEmptyContentXml( - content_name_b, content_type_b, kTransportType); - if (bundle) { - content_xml += JingleGroupInfoXml(content_name_a, content_name_b); - } - } - return JingleInitiateActionXml(content_xml); -} - -std::string GingleAcceptXml(const std::string& content_type) { - return GingleSessionXml( - "accept", - GingleDescriptionXml(content_type)); -} - -std::string JingleAcceptXml(const std::string& content_name_a, - const std::string& content_type_a, - const std::string& content_name_b, - const std::string& content_type_b, - bool bundle = false) { - std::string content_xml; - if (content_name_b.empty()) { - content_xml = JingleEmptyContentXml( - content_name_a, content_type_a, kTransportType); - } else { - content_xml = JingleEmptyContentXml( - content_name_a, content_type_a, kTransportType) + - JingleEmptyContentXml( - content_name_b, content_type_b, kTransportType); - } - if (bundle) { - content_xml += JingleGroupInfoXml(content_name_a, content_name_b); - } - - return JingleActionXml("session-accept", content_xml); -} - -std::string Gingle2CandidatesXml(const std::string& channel_name, - int port_index0, - int port_index1) { - return GingleSessionXml( - "candidates", - P2pCandidateXml(channel_name, port_index0) + - P2pCandidateXml(channel_name, port_index1)); -} - -std::string Gingle4CandidatesXml(const std::string& channel_name_a, - int port_index0, - int port_index1, - const std::string& channel_name_b, - int port_index2, - int port_index3) { - return GingleSessionXml( - "candidates", - P2pCandidateXml(channel_name_a, port_index0) + - P2pCandidateXml(channel_name_a, port_index1) + - P2pCandidateXml(channel_name_b, port_index2) + - P2pCandidateXml(channel_name_b, port_index3)); -} - -std::string Jingle2TransportInfoXml(const std::string& content_name, - const std::string& channel_name, - int port_index0, - int port_index1) { - return JingleActionXml( - "transport-info", - JingleTransportContentXml( - content_name, kTransportType, - P2pCandidateXml(channel_name, port_index0) + - P2pCandidateXml(channel_name, port_index1))); -} - -std::string Jingle4TransportInfoXml(const std::string& content_name, - const std::string& channel_name_a, - int port_index0, - int port_index1, - const std::string& channel_name_b, - int port_index2, - int port_index3) { - return JingleActionXml( - "transport-info", - JingleTransportContentXml( - content_name, kTransportType, - P2pCandidateXml(channel_name_a, port_index0) + - P2pCandidateXml(channel_name_a, port_index1) + - P2pCandidateXml(channel_name_b, port_index2) + - P2pCandidateXml(channel_name_b, port_index3))); -} - -std::string JingleDescriptionInfoXml(const std::string& content_name, - const std::string& content_type) { - return JingleActionXml( - "description-info", - JingleContentXml(content_name, content_type, "", "")); -} - -std::string GingleRejectXml(const std::string& reason) { - return GingleSessionXml( - "reject", - "<" + reason + "/>"); -} - -std::string JingleTerminateXml(const std::string& reason) { - return JingleActionXml( - "session-terminate", - "<" + reason + "/>"); -} - -std::string GingleTerminateXml(const std::string& reason) { - return GingleSessionXml( - "terminate", - "<" + reason + "/>"); -} - -std::string GingleRedirectXml(const std::string& intitiate, - const std::string& target) { - return intitiate + - "" - "" - "xmpp:" + target + - "" - ""; -} - -std::string JingleRedirectXml(const std::string& intitiate, - const std::string& target) { - return intitiate + - "" - "" - "xmpp:" + target + - "" - ""; -} - -std::string InitiateXml(SignalingProtocol protocol, - const std::string& gingle_content_type, - const std::string& content_name_a, - const std::string& content_type_a, - const std::string& content_name_b, - const std::string& content_type_b, - bool bundle = false) { - switch (protocol) { - case PROTOCOL_JINGLE: - return JingleInitiateXml(content_name_a, content_type_a, - content_name_b, content_type_b, - bundle); - case PROTOCOL_GINGLE: - return GingleInitiateXml(gingle_content_type); - case PROTOCOL_HYBRID: - return JingleInitiateXml(content_name_a, content_type_a, - content_name_b, content_type_b) + - GingleInitiateXml(gingle_content_type); - } - return ""; -} - -std::string InitiateXml(SignalingProtocol protocol, - const std::string& content_name, - const std::string& content_type) { - return InitiateXml(protocol, - content_type, - content_name, content_type, - "", ""); -} - -std::string AcceptXml(SignalingProtocol protocol, - const std::string& gingle_content_type, - const std::string& content_name_a, - const std::string& content_type_a, - const std::string& content_name_b, - const std::string& content_type_b, - bool bundle = false) { - switch (protocol) { - case PROTOCOL_JINGLE: - return JingleAcceptXml(content_name_a, content_type_a, - content_name_b, content_type_b, bundle); - case PROTOCOL_GINGLE: - return GingleAcceptXml(gingle_content_type); - case PROTOCOL_HYBRID: - return - JingleAcceptXml(content_name_a, content_type_a, - content_name_b, content_type_b) + - GingleAcceptXml(gingle_content_type); - } - return ""; -} - - -std::string AcceptXml(SignalingProtocol protocol, - const std::string& content_name, - const std::string& content_type, - bool bundle = false) { - return AcceptXml(protocol, - content_type, - content_name, content_type, - "", ""); -} - -std::string TransportInfo2Xml(SignalingProtocol protocol, - const std::string& content_name, - const std::string& channel_name, - int port_index0, - int port_index1) { - switch (protocol) { - case PROTOCOL_JINGLE: - return Jingle2TransportInfoXml( - content_name, - channel_name, port_index0, port_index1); - case PROTOCOL_GINGLE: - return Gingle2CandidatesXml( - channel_name, port_index0, port_index1); - case PROTOCOL_HYBRID: - return - Jingle2TransportInfoXml( - content_name, - channel_name, port_index0, port_index1) + - Gingle2CandidatesXml( - channel_name, port_index0, port_index1); - } - return ""; -} - -std::string TransportInfo4Xml(SignalingProtocol protocol, - const std::string& content_name, - const std::string& channel_name_a, - int port_index0, - int port_index1, - const std::string& channel_name_b, - int port_index2, - int port_index3) { - switch (protocol) { - case PROTOCOL_JINGLE: - return Jingle4TransportInfoXml( - content_name, - channel_name_a, port_index0, port_index1, - channel_name_b, port_index2, port_index3); - case PROTOCOL_GINGLE: - return Gingle4CandidatesXml( - channel_name_a, port_index0, port_index1, - channel_name_b, port_index2, port_index3); - case PROTOCOL_HYBRID: - return - Jingle4TransportInfoXml( - content_name, - channel_name_a, port_index0, port_index1, - channel_name_b, port_index2, port_index3) + - Gingle4CandidatesXml( - channel_name_a, port_index0, port_index1, - channel_name_b, port_index2, port_index3); - } - return ""; -} - -std::string RejectXml(SignalingProtocol protocol, - const std::string& reason) { - switch (protocol) { - case PROTOCOL_JINGLE: - return JingleTerminateXml(reason); - case PROTOCOL_GINGLE: - return GingleRejectXml(reason); - case PROTOCOL_HYBRID: - return JingleTerminateXml(reason) + - GingleRejectXml(reason); - } - return ""; -} - -std::string TerminateXml(SignalingProtocol protocol, - const std::string& reason) { - switch (protocol) { - case PROTOCOL_JINGLE: - return JingleTerminateXml(reason); - case PROTOCOL_GINGLE: - return GingleTerminateXml(reason); - case PROTOCOL_HYBRID: - return JingleTerminateXml(reason) + - GingleTerminateXml(reason); - } - return ""; -} - -std::string RedirectXml(SignalingProtocol protocol, - const std::string& initiate, - const std::string& target) { - switch (protocol) { - case PROTOCOL_JINGLE: - return JingleRedirectXml(initiate, target); - case PROTOCOL_GINGLE: - return GingleRedirectXml(initiate, target); - default: - break; - } - return ""; -} - -// TODO: Break out and join with fakeportallocator.h -class TestPortAllocatorSession : public cricket::PortAllocatorSession { - public: - TestPortAllocatorSession(const std::string& content_name, - int component, - const std::string& ice_ufrag, - const std::string& ice_pwd, - const int port_offset) - : PortAllocatorSession(content_name, component, ice_ufrag, ice_pwd, 0), - port_offset_(port_offset), - ports_(kNumPorts), - address_("127.0.0.1", 0), - network_("network", "unittest", - rtc::IPAddress(INADDR_LOOPBACK), 8), - socket_factory_(rtc::Thread::Current()), - running_(false) { - network_.AddIP(address_.ipaddr()); - } - - ~TestPortAllocatorSession() { - for (size_t i = 0; i < ports_.size(); i++) - delete ports_[i]; - } - - virtual void StartGettingPorts() { - for (int i = 0; i < kNumPorts; i++) { - int index = port_offset_ + i; - ports_[i] = cricket::UDPPort::Create( - rtc::Thread::Current(), &socket_factory_, - &network_, address_.ipaddr(), GetPort(index), GetPort(index), - GetUsername(index), GetPassword(index), - std::string()); - AddPort(ports_[i]); - } - running_ = true; - } - - virtual void StopGettingPorts() { running_ = false; } - virtual bool IsGettingPorts() { return running_; } - - void AddPort(cricket::Port* port) { - port->set_component(component_); - port->set_generation(0); - port->SignalDestroyed.connect( - this, &TestPortAllocatorSession::OnPortDestroyed); - port->SignalPortComplete.connect( - this, &TestPortAllocatorSession::OnPortComplete); - port->PrepareAddress(); - SignalPortReady(this, port); - } - - void OnPortDestroyed(cricket::PortInterface* port) { - for (size_t i = 0; i < ports_.size(); i++) { - if (ports_[i] == port) - ports_[i] = NULL; - } - } - - void OnPortComplete(cricket::Port* port) { - SignalCandidatesReady(this, port->Candidates()); - } - - private: - int port_offset_; - std::vector ports_; - rtc::SocketAddress address_; - rtc::Network network_; - rtc::BasicPacketSocketFactory socket_factory_; - bool running_; -}; - -class TestPortAllocator : public cricket::PortAllocator { - public: - TestPortAllocator() : port_offset_(0) {} - - virtual cricket::PortAllocatorSession* - CreateSessionInternal( - const std::string& content_name, - int component, - const std::string& ice_ufrag, - const std::string& ice_pwd) { - port_offset_ += 2; - return new TestPortAllocatorSession(content_name, component, - ice_ufrag, ice_pwd, port_offset_ - 2); - } - - int port_offset_; -}; - -class TestContentDescription : public cricket::ContentDescription { - public: - explicit TestContentDescription(const std::string& gingle_content_type, - const std::string& content_type) - : gingle_content_type(gingle_content_type), - content_type(content_type) { - } - virtual ContentDescription* Copy() const { - return new TestContentDescription(*this); - } - - std::string gingle_content_type; - std::string content_type; -}; - -cricket::SessionDescription* NewTestSessionDescription( - const std::string gingle_content_type, - const std::string& content_name_a, const std::string& content_type_a, - const std::string& content_name_b, const std::string& content_type_b) { - - cricket::SessionDescription* offer = new cricket::SessionDescription(); - offer->AddContent(content_name_a, content_type_a, - new TestContentDescription(gingle_content_type, - content_type_a)); - cricket::TransportDescription desc(cricket::NS_GINGLE_P2P, - std::string(), std::string()); - offer->AddTransportInfo(cricket::TransportInfo(content_name_a, desc)); - - if (content_name_a != content_name_b) { - offer->AddContent(content_name_b, content_type_b, - new TestContentDescription(gingle_content_type, - content_type_b)); - offer->AddTransportInfo(cricket::TransportInfo(content_name_b, desc)); - } - return offer; -} - -cricket::SessionDescription* NewTestSessionDescription( - const std::string& content_name, const std::string& content_type) { - - cricket::SessionDescription* offer = new cricket::SessionDescription(); - offer->AddContent(content_name, content_type, - new TestContentDescription(content_type, - content_type)); - offer->AddTransportInfo(cricket::TransportInfo - (content_name, cricket::TransportDescription( - cricket::NS_GINGLE_P2P, - std::string(), std::string()))); - return offer; -} - -struct TestSessionClient: public cricket::SessionClient, - public sigslot::has_slots<> { - public: - TestSessionClient() { - } - - ~TestSessionClient() { - } - - virtual bool ParseContent(SignalingProtocol protocol, - const buzz::XmlElement* elem, - cricket::ContentDescription** content, - cricket::ParseError* error) { - std::string content_type; - std::string gingle_content_type; - if (protocol == PROTOCOL_GINGLE) { - gingle_content_type = elem->Name().Namespace(); - } else { - content_type = elem->Name().Namespace(); - } - - *content = new TestContentDescription(gingle_content_type, content_type); - return true; - } - - virtual bool WriteContent(SignalingProtocol protocol, - const cricket::ContentDescription* untyped_content, - buzz::XmlElement** elem, - cricket::WriteError* error) { - const TestContentDescription* content = - static_cast(untyped_content); - std::string content_type = (protocol == PROTOCOL_GINGLE ? - content->gingle_content_type : - content->content_type); - *elem = new buzz::XmlElement( - buzz::QName(content_type, "description"), true); - return true; - } - - void OnSessionCreate(cricket::Session* session, bool initiate) { - } - - void OnSessionDestroy(cricket::Session* session) { - } -}; - -struct ChannelHandler : sigslot::has_slots<> { - explicit ChannelHandler(cricket::TransportChannel* p, const std::string& name) - : channel(p), last_readable(false), last_writable(false), data_count(0), - last_size(0), name(name) { - p->SignalReadableState.connect(this, &ChannelHandler::OnReadableState); - p->SignalWritableState.connect(this, &ChannelHandler::OnWritableState); - p->SignalReadPacket.connect(this, &ChannelHandler::OnReadPacket); - } - - bool writable() const { - return last_writable && channel->writable(); - } - - bool readable() const { - return last_readable && channel->readable(); - } - - void OnReadableState(cricket::TransportChannel* p) { - EXPECT_EQ(channel, p); - last_readable = channel->readable(); - } - - void OnWritableState(cricket::TransportChannel* p) { - EXPECT_EQ(channel, p); - last_writable = channel->writable(); - } - - void OnReadPacket(cricket::TransportChannel* p, const char* buf, - size_t size, const rtc::PacketTime& time, int flags) { - if (memcmp(buf, name.c_str(), name.size()) != 0) - return; // drop packet if packet doesn't belong to this channel. This - // can happen when transport channels are muxed together. - buf += name.size(); // Remove channel name from the message. - size -= name.size(); // Decrement size by channel name string size. - EXPECT_EQ(channel, p); - EXPECT_LE(size, sizeof(last_data)); - data_count += 1; - last_size = size; - memcpy(last_data, buf, size); - } - - void Send(const char* data, size_t size) { - rtc::PacketOptions options; - std::string data_with_id(name); - data_with_id += data; - int result = channel->SendPacket(data_with_id.c_str(), data_with_id.size(), - options, 0); - EXPECT_EQ(static_cast(data_with_id.size()), result); - } - - cricket::TransportChannel* channel; - bool last_readable, last_writable; - int data_count; - char last_data[4096]; - size_t last_size; - std::string name; -}; - -void PrintStanza(const std::string& message, - const buzz::XmlElement* stanza) { - printf("%s: %s\n", message.c_str(), stanza->Str().c_str()); -} - -class TestClient : public sigslot::has_slots<> { - public: - // TODO: Add channel_component_a/b as inputs to the ctor. - TestClient(cricket::PortAllocator* port_allocator, - int* next_message_id, - const std::string& local_name, - SignalingProtocol start_protocol, - const std::string& content_type, - const std::string& content_name_a, - const std::string& channel_name_a, - const std::string& content_name_b, - const std::string& channel_name_b) { - Construct(port_allocator, next_message_id, local_name, start_protocol, - content_type, content_name_a, channel_name_a, - content_name_b, channel_name_b); - } - - ~TestClient() { - if (session) { - session_manager->DestroySession(session); - EXPECT_EQ(1U, session_destroyed_count); - } - delete session_manager; - delete client; - for (std::deque::iterator it = sent_stanzas.begin(); - it != sent_stanzas.end(); ++it) { - delete *it; - } - } - - void Construct(cricket::PortAllocator* pa, - int* message_id, - const std::string& lname, - SignalingProtocol protocol, - const std::string& cont_type, - const std::string& cont_name_a, - const std::string& chan_name_a, - const std::string& cont_name_b, - const std::string& chan_name_b) { - port_allocator_ = pa; - next_message_id = message_id; - local_name = lname; - start_protocol = protocol; - content_type = cont_type; - content_name_a = cont_name_a; - channel_name_a = chan_name_a; - content_name_b = cont_name_b; - channel_name_b = chan_name_b; - session_created_count = 0; - session_destroyed_count = 0; - session_remote_description_update_count = 0; - new_local_description = false; - new_remote_description = false; - last_content_action = cricket::CA_OFFER; - last_content_source = cricket::CS_LOCAL; - session = NULL; - last_session_state = cricket::BaseSession::STATE_INIT; - blow_up_on_error = true; - error_count = 0; - - session_manager = new cricket::SessionManager(port_allocator_); - session_manager->SignalSessionCreate.connect( - this, &TestClient::OnSessionCreate); - session_manager->SignalSessionDestroy.connect( - this, &TestClient::OnSessionDestroy); - session_manager->SignalOutgoingMessage.connect( - this, &TestClient::OnOutgoingMessage); - - client = new TestSessionClient(); - session_manager->AddClient(content_type, client); - EXPECT_EQ(client, session_manager->GetClient(content_type)); - } - - uint32 sent_stanza_count() const { - return static_cast(sent_stanzas.size()); - } - - const buzz::XmlElement* stanza() const { - return last_expected_sent_stanza.get(); - } - - cricket::BaseSession::State session_state() const { - EXPECT_EQ(last_session_state, session->state()); - return session->state(); - } - - void SetSessionState(cricket::BaseSession::State state) { - session->SetState(state); - EXPECT_EQ_WAIT(last_session_state, session->state(), kEventTimeout); - } - - void CreateSession() { - session_manager->CreateSession(local_name, content_type); - } - - void DeliverStanza(const buzz::XmlElement* stanza) { - session_manager->OnIncomingMessage(stanza); - } - - void DeliverStanza(const std::string& str) { - buzz::XmlElement* stanza = buzz::XmlElement::ForStr(str); - session_manager->OnIncomingMessage(stanza); - delete stanza; - } - - void DeliverAckToLastStanza() { - const buzz::XmlElement* orig_stanza = stanza(); - const buzz::XmlElement* response_stanza = - buzz::XmlElement::ForStr(IqAck(orig_stanza->Attr(buzz::QN_IQ), "", "")); - session_manager->OnIncomingResponse(orig_stanza, response_stanza); - delete response_stanza; - } - - void ExpectSentStanza(const std::string& expected) { - EXPECT_TRUE(!sent_stanzas.empty()) << - "Found no stanza when expected " << expected; - - last_expected_sent_stanza.reset(sent_stanzas.front()); - sent_stanzas.pop_front(); - - std::string actual = last_expected_sent_stanza->Str(); - EXPECT_EQ(expected, actual); - } - - void SkipUnsentStanza() { - GetNextOutgoingMessageID(); - } - - bool HasTransport(const std::string& content_name) const { - ASSERT(session != NULL); - const cricket::Transport* transport = session->GetTransport(content_name); - return transport != NULL && (kTransportType == transport->type()); - } - - bool HasChannel(const std::string& content_name, - int component) const { - ASSERT(session != NULL); - const cricket::TransportChannel* channel = - session->GetChannel(content_name, component); - return channel != NULL && (component == channel->component()); - } - - cricket::TransportChannel* GetChannel(const std::string& content_name, - int component) const { - ASSERT(session != NULL); - return session->GetChannel(content_name, component); - } - - void OnSessionCreate(cricket::Session* created_session, bool initiate) { - session_created_count += 1; - - session = created_session; - session->set_current_protocol(start_protocol); - session->SignalState.connect(this, &TestClient::OnSessionState); - session->SignalError.connect(this, &TestClient::OnSessionError); - session->SignalRemoteDescriptionUpdate.connect( - this, &TestClient::OnSessionRemoteDescriptionUpdate); - session->SignalNewLocalDescription.connect( - this, &TestClient::OnNewLocalDescription); - session->SignalNewRemoteDescription.connect( - this, &TestClient::OnNewRemoteDescription); - - CreateChannels(); - } - - void OnSessionDestroy(cricket::Session *session) { - session_destroyed_count += 1; - } - - void OnSessionState(cricket::BaseSession* session, - cricket::BaseSession::State state) { - // EXPECT_EQ does not allow use of this, hence the tmp variable. - cricket::BaseSession* tmp = this->session; - EXPECT_EQ(tmp, session); - last_session_state = state; - } - - void OnSessionError(cricket::BaseSession* session, - cricket::BaseSession::Error error) { - // EXPECT_EQ does not allow use of this, hence the tmp variable. - cricket::BaseSession* tmp = this->session; - EXPECT_EQ(tmp, session); - if (blow_up_on_error) { - EXPECT_TRUE(false); - } else { - error_count++; - } - } - - void OnSessionRemoteDescriptionUpdate(cricket::BaseSession* session, - const cricket::ContentInfos& contents) { - session_remote_description_update_count++; - } - - void OnNewLocalDescription(cricket::BaseSession* session, - cricket::ContentAction action) { - new_local_description = true; - last_content_action = action; - last_content_source = cricket::CS_LOCAL; - } - - void OnNewRemoteDescription(cricket::BaseSession* session, - cricket::ContentAction action) { - new_remote_description = true; - last_content_action = action; - last_content_source = cricket::CS_REMOTE; - } - - void PrepareCandidates() { - session_manager->OnSignalingReady(); - } - - void OnOutgoingMessage(cricket::SessionManager* manager, - const buzz::XmlElement* stanza) { - buzz::XmlElement* elem = new buzz::XmlElement(*stanza); - EXPECT_TRUE(elem->Name() == buzz::QN_IQ); - EXPECT_TRUE(elem->HasAttr(buzz::QN_TO)); - EXPECT_FALSE(elem->HasAttr(buzz::QN_FROM)); - EXPECT_TRUE(elem->HasAttr(buzz::QN_TYPE)); - EXPECT_TRUE((elem->Attr(buzz::QN_TYPE) == "set") || - (elem->Attr(buzz::QN_TYPE) == "result") || - (elem->Attr(buzz::QN_TYPE) == "error")); - - elem->SetAttr(buzz::QN_FROM, local_name); - if (elem->Attr(buzz::QN_TYPE) == "set") { - EXPECT_FALSE(elem->HasAttr(buzz::QN_ID)); - elem->SetAttr(buzz::QN_ID, GetNextOutgoingMessageID()); - } - - // Uncommenting this is useful for debugging. - // PrintStanza("OutgoingMessage", elem); - sent_stanzas.push_back(elem); - } - - std::string GetNextOutgoingMessageID() { - int message_id = (*next_message_id)++; - std::ostringstream ost; - ost << message_id; - return ost.str(); - } - - void CreateChannels() { - ASSERT(session != NULL); - // We either have a single content with multiple components (RTP/RTCP), or - // multiple contents with single components, but not both. - int component_a = 1; - int component_b = (content_name_a == content_name_b) ? 2 : 1; - chan_a.reset(new ChannelHandler( - session->CreateChannel(content_name_a, channel_name_a, component_a), - channel_name_a)); - chan_b.reset(new ChannelHandler( - session->CreateChannel(content_name_b, channel_name_b, component_b), - channel_name_b)); - } - - int* next_message_id; - std::string local_name; - SignalingProtocol start_protocol; - std::string content_type; - std::string content_name_a; - std::string channel_name_a; - std::string content_name_b; - std::string channel_name_b; - - uint32 session_created_count; - uint32 session_destroyed_count; - uint32 session_remote_description_update_count; - bool new_local_description; - bool new_remote_description; - cricket::ContentAction last_content_action; - cricket::ContentSource last_content_source; - std::deque sent_stanzas; - rtc::scoped_ptr last_expected_sent_stanza; - - cricket::SessionManager* session_manager; - TestSessionClient* client; - cricket::PortAllocator* port_allocator_; - cricket::Session* session; - cricket::BaseSession::State last_session_state; - rtc::scoped_ptr chan_a; - rtc::scoped_ptr chan_b; - bool blow_up_on_error; - int error_count; -}; - -class SessionTest : public testing::Test { - protected: - virtual void SetUp() { - // Seed needed for each test to satisfy expectations. - rtc::SetRandomTestMode(true); - } - - virtual void TearDown() { - rtc::SetRandomTestMode(false); - } - - // Tests sending data between two clients, over two channels. - void TestSendRecv(ChannelHandler* chan1a, - ChannelHandler* chan1b, - ChannelHandler* chan2a, - ChannelHandler* chan2b) { - const char* dat1a = "spamspamspamspamspamspamspambakedbeansspam"; - const char* dat2a = "mapssnaebdekabmapsmapsmapsmapsmapsmapsmaps"; - const char* dat1b = "Lobster Thermidor a Crevette with a mornay sauce..."; - const char* dat2b = "...ecuas yanrom a htiw etteverC a rodimrehT retsboL"; - - for (int i = 0; i < 20; i++) { - chan1a->Send(dat1a, strlen(dat1a)); - chan1b->Send(dat1b, strlen(dat1b)); - chan2a->Send(dat2a, strlen(dat2a)); - chan2b->Send(dat2b, strlen(dat2b)); - - EXPECT_EQ_WAIT(i + 1, chan1a->data_count, kEventTimeout); - EXPECT_EQ_WAIT(i + 1, chan1b->data_count, kEventTimeout); - EXPECT_EQ_WAIT(i + 1, chan2a->data_count, kEventTimeout); - EXPECT_EQ_WAIT(i + 1, chan2b->data_count, kEventTimeout); - - EXPECT_EQ(strlen(dat2a), chan1a->last_size); - EXPECT_EQ(strlen(dat2b), chan1b->last_size); - EXPECT_EQ(strlen(dat1a), chan2a->last_size); - EXPECT_EQ(strlen(dat1b), chan2b->last_size); - - EXPECT_EQ(0, memcmp(chan1a->last_data, dat2a, strlen(dat2a))); - EXPECT_EQ(0, memcmp(chan1b->last_data, dat2b, strlen(dat2b))); - EXPECT_EQ(0, memcmp(chan2a->last_data, dat1a, strlen(dat1a))); - EXPECT_EQ(0, memcmp(chan2b->last_data, dat1b, strlen(dat1b))); - } - } - - // Test an initiate from one client to another, each with - // independent initial protocols. Checks for the correct initiates, - // candidates, and accept messages, and tests that working network - // channels are established. - void TestSession(SignalingProtocol initiator_protocol, - SignalingProtocol responder_protocol, - SignalingProtocol resulting_protocol, - const std::string& gingle_content_type, - const std::string& content_type, - const std::string& content_name_a, - const std::string& channel_name_a, - const std::string& content_name_b, - const std::string& channel_name_b, - const std::string& initiate_xml, - const std::string& transport_info_a_xml, - const std::string& transport_info_b_xml, - const std::string& transport_info_reply_a_xml, - const std::string& transport_info_reply_b_xml, - const std::string& accept_xml, - bool bundle = false) { - rtc::scoped_ptr allocator( - new TestPortAllocator()); - int next_message_id = 0; - - rtc::scoped_ptr initiator( - new TestClient(allocator.get(), &next_message_id, - kInitiator, initiator_protocol, - content_type, - content_name_a, channel_name_a, - content_name_b, channel_name_b)); - rtc::scoped_ptr responder( - new TestClient(allocator.get(), &next_message_id, - kResponder, responder_protocol, - content_type, - content_name_a, channel_name_a, - content_name_b, channel_name_b)); - - // Create Session and check channels and state. - initiator->CreateSession(); - EXPECT_EQ(1U, initiator->session_created_count); - EXPECT_EQ(kSessionId, initiator->session->id()); - EXPECT_EQ(initiator->session->local_name(), kInitiator); - EXPECT_EQ(cricket::BaseSession::STATE_INIT, - initiator->session_state()); - - // See comment in CreateChannels about how we choose component IDs. - int component_a = 1; - int component_b = (content_name_a == content_name_b) ? 2 : 1; - EXPECT_TRUE(initiator->HasTransport(content_name_a)); - EXPECT_TRUE(initiator->HasChannel(content_name_a, component_a)); - EXPECT_TRUE(initiator->HasTransport(content_name_b)); - EXPECT_TRUE(initiator->HasChannel(content_name_b, component_b)); - - // Initiate and expect initiate message sent. - cricket::SessionDescription* offer = NewTestSessionDescription( - gingle_content_type, - content_name_a, content_type, - content_name_b, content_type); - if (bundle) { - cricket::ContentGroup group(cricket::GROUP_TYPE_BUNDLE); - group.AddContentName(content_name_a); - group.AddContentName(content_name_b); - EXPECT_TRUE(group.HasContentName(content_name_a)); - EXPECT_TRUE(group.HasContentName(content_name_b)); - offer->AddGroup(group); - } - EXPECT_TRUE(initiator->session->Initiate(kResponder, offer)); - EXPECT_EQ(initiator->session->remote_name(), kResponder); - EXPECT_EQ(initiator->session->local_description(), offer); - - EXPECT_TRUE_WAIT(initiator->sent_stanza_count() > 0, kEventTimeout); - EXPECT_EQ(cricket::BaseSession::STATE_SENTINITIATE, - initiator->session_state()); - - initiator->ExpectSentStanza( - IqSet("0", kInitiator, kResponder, initiate_xml)); - - // Deliver the initiate. Expect ack and session created with - // transports. - responder->DeliverStanza(initiator->stanza()); - responder->ExpectSentStanza( - IqAck("0", kResponder, kInitiator)); - EXPECT_EQ(0U, responder->sent_stanza_count()); - - EXPECT_EQ(1U, responder->session_created_count); - EXPECT_EQ(kSessionId, responder->session->id()); - EXPECT_EQ(responder->session->local_name(), kResponder); - EXPECT_EQ(responder->session->remote_name(), kInitiator); - EXPECT_EQ(cricket::BaseSession::STATE_RECEIVEDINITIATE, - responder->session_state()); - - EXPECT_TRUE(responder->HasTransport(content_name_a)); - EXPECT_TRUE(responder->HasChannel(content_name_a, component_a)); - EXPECT_TRUE(responder->HasTransport(content_name_b)); - EXPECT_TRUE(responder->HasChannel(content_name_b, component_b)); - - // Expect transport-info message from initiator. - // But don't send candidates until initiate ack is received. - initiator->PrepareCandidates(); - WAIT(initiator->sent_stanza_count() > 0, 100); - EXPECT_EQ(0U, initiator->sent_stanza_count()); - initiator->DeliverAckToLastStanza(); - EXPECT_TRUE_WAIT(initiator->sent_stanza_count() > 0, kEventTimeout); - initiator->ExpectSentStanza( - IqSet("1", kInitiator, kResponder, transport_info_a_xml)); - - // Deliver transport-info and expect ack. - responder->DeliverStanza(initiator->stanza()); - responder->ExpectSentStanza( - IqAck("1", kResponder, kInitiator)); - - if (!transport_info_b_xml.empty()) { - // Expect second transport-info message from initiator. - EXPECT_TRUE_WAIT(initiator->sent_stanza_count() > 0, kEventTimeout); - initiator->ExpectSentStanza( - IqSet("2", kInitiator, kResponder, transport_info_b_xml)); - EXPECT_EQ(0U, initiator->sent_stanza_count()); - - // Deliver second transport-info message and expect ack. - responder->DeliverStanza(initiator->stanza()); - responder->ExpectSentStanza( - IqAck("2", kResponder, kInitiator)); - } else { - EXPECT_EQ(0U, initiator->sent_stanza_count()); - EXPECT_EQ(0U, responder->sent_stanza_count()); - initiator->SkipUnsentStanza(); - } - - // Expect reply transport-info message from responder. - responder->PrepareCandidates(); - EXPECT_TRUE_WAIT(responder->sent_stanza_count() > 0, kEventTimeout); - responder->ExpectSentStanza( - IqSet("3", kResponder, kInitiator, transport_info_reply_a_xml)); - - // Deliver reply transport-info and expect ack. - initiator->DeliverStanza(responder->stanza()); - initiator->ExpectSentStanza( - IqAck("3", kInitiator, kResponder)); - - if (!transport_info_reply_b_xml.empty()) { - // Expect second reply transport-info message from responder. - EXPECT_TRUE_WAIT(responder->sent_stanza_count() > 0, kEventTimeout); - responder->ExpectSentStanza( - IqSet("4", kResponder, kInitiator, transport_info_reply_b_xml)); - EXPECT_EQ(0U, responder->sent_stanza_count()); - - // Deliver second reply transport-info message and expect ack. - initiator->DeliverStanza(responder->stanza()); - initiator->ExpectSentStanza( - IqAck("4", kInitiator, kResponder)); - EXPECT_EQ(0U, initiator->sent_stanza_count()); - } else { - EXPECT_EQ(0U, initiator->sent_stanza_count()); - EXPECT_EQ(0U, responder->sent_stanza_count()); - responder->SkipUnsentStanza(); - } - - // The channels should be able to become writable at this point. This - // requires pinging, so it may take a little while. - EXPECT_TRUE_WAIT(initiator->chan_a->writable() && - initiator->chan_a->readable(), kEventTimeout); - EXPECT_TRUE_WAIT(initiator->chan_b->writable() && - initiator->chan_b->readable(), kEventTimeout); - EXPECT_TRUE_WAIT(responder->chan_a->writable() && - responder->chan_a->readable(), kEventTimeout); - EXPECT_TRUE_WAIT(responder->chan_b->writable() && - responder->chan_b->readable(), kEventTimeout); - - // Accept the session and expect accept stanza. - cricket::SessionDescription* answer = NewTestSessionDescription( - gingle_content_type, - content_name_a, content_type, - content_name_b, content_type); - if (bundle) { - cricket::ContentGroup group(cricket::GROUP_TYPE_BUNDLE); - group.AddContentName(content_name_a); - group.AddContentName(content_name_b); - EXPECT_TRUE(group.HasContentName(content_name_a)); - EXPECT_TRUE(group.HasContentName(content_name_b)); - answer->AddGroup(group); - } - EXPECT_TRUE(responder->session->Accept(answer)); - EXPECT_EQ(responder->session->local_description(), answer); - - responder->ExpectSentStanza( - IqSet("5", kResponder, kInitiator, accept_xml)); - - EXPECT_EQ(0U, responder->sent_stanza_count()); - - // Deliver the accept message and expect an ack. - initiator->DeliverStanza(responder->stanza()); - EXPECT_TRUE_WAIT(initiator->sent_stanza_count() > 0, kEventTimeout); - initiator->ExpectSentStanza( - IqAck("5", kInitiator, kResponder)); - EXPECT_EQ(0U, initiator->sent_stanza_count()); - - // Both sessions should be in progress and have functioning - // channels. - EXPECT_EQ(resulting_protocol, initiator->session->current_protocol()); - EXPECT_EQ(resulting_protocol, responder->session->current_protocol()); - EXPECT_EQ_WAIT(cricket::BaseSession::STATE_INPROGRESS, - initiator->session_state(), kEventTimeout); - EXPECT_EQ_WAIT(cricket::BaseSession::STATE_INPROGRESS, - responder->session_state(), kEventTimeout); - if (bundle) { - cricket::TransportChannel* initiator_chan_a = initiator->chan_a->channel; - cricket::TransportChannel* initiator_chan_b = initiator->chan_b->channel; - - // Since we know these are TransportChannelProxy, type cast it. - cricket::TransportChannelProxy* initiator_proxy_chan_a = - static_cast(initiator_chan_a); - cricket::TransportChannelProxy* initiator_proxy_chan_b = - static_cast(initiator_chan_b); - EXPECT_TRUE(initiator_proxy_chan_a->impl() != NULL); - EXPECT_TRUE(initiator_proxy_chan_b->impl() != NULL); - EXPECT_EQ(initiator_proxy_chan_a->impl(), initiator_proxy_chan_b->impl()); - - cricket::TransportChannel* responder_chan_a = responder->chan_a->channel; - cricket::TransportChannel* responder_chan_b = responder->chan_b->channel; - - // Since we know these are TransportChannelProxy, type cast it. - cricket::TransportChannelProxy* responder_proxy_chan_a = - static_cast(responder_chan_a); - cricket::TransportChannelProxy* responder_proxy_chan_b = - static_cast(responder_chan_b); - EXPECT_TRUE(responder_proxy_chan_a->impl() != NULL); - EXPECT_TRUE(responder_proxy_chan_b->impl() != NULL); - EXPECT_EQ(responder_proxy_chan_a->impl(), responder_proxy_chan_b->impl()); - } - TestSendRecv(initiator->chan_a.get(), initiator->chan_b.get(), - responder->chan_a.get(), responder->chan_b.get()); - - if (resulting_protocol == PROTOCOL_JINGLE) { - // Deliver a description-info message to the initiator and check if the - // content description changes. - EXPECT_EQ(0U, initiator->session_remote_description_update_count); - - const cricket::SessionDescription* old_session_desc = - initiator->session->remote_description(); - const cricket::ContentInfo* old_content_a = - old_session_desc->GetContentByName(content_name_a); - const cricket::ContentDescription* old_content_desc_a = - old_content_a->description; - const cricket::ContentInfo* old_content_b = - old_session_desc->GetContentByName(content_name_b); - const cricket::ContentDescription* old_content_desc_b = - old_content_b->description; - EXPECT_TRUE(old_content_desc_a != NULL); - EXPECT_TRUE(old_content_desc_b != NULL); - - LOG(LS_INFO) << "A " << old_content_a->name; - LOG(LS_INFO) << "B " << old_content_b->name; - - std::string description_info_xml = - JingleDescriptionInfoXml(content_name_a, content_type); - initiator->DeliverStanza( - IqSet("6", kResponder, kInitiator, description_info_xml)); - responder->SkipUnsentStanza(); - EXPECT_EQ(1U, initiator->session_remote_description_update_count); - - const cricket::SessionDescription* new_session_desc = - initiator->session->remote_description(); - const cricket::ContentInfo* new_content_a = - new_session_desc->GetContentByName(content_name_a); - const cricket::ContentDescription* new_content_desc_a = - new_content_a->description; - const cricket::ContentInfo* new_content_b = - new_session_desc->GetContentByName(content_name_b); - const cricket::ContentDescription* new_content_desc_b = - new_content_b->description; - EXPECT_TRUE(new_content_desc_a != NULL); - EXPECT_TRUE(new_content_desc_b != NULL); - - // TODO: We used to replace contents from an update, but - // that no longer works with partial updates. We need to figure out - // a way to merge patial updates into contents. For now, users of - // Session should listen to SignalRemoteDescriptionUpdate and handle - // updates. They should not expect remote_description to be the - // latest value. - // See session.cc OnDescriptionInfoMessage. - - // EXPECT_NE(old_content_desc_a, new_content_desc_a); - - // if (content_name_a != content_name_b) { - // // If content_name_a != content_name_b, then b's content description - // // should not have changed since the description-info message only - // // contained an update for content_name_a. - // EXPECT_EQ(old_content_desc_b, new_content_desc_b); - // } - - EXPECT_TRUE_WAIT(initiator->sent_stanza_count() > 0, kEventTimeout); - initiator->ExpectSentStanza( - IqAck("6", kInitiator, kResponder)); - EXPECT_EQ(0U, initiator->sent_stanza_count()); - } else { - responder->SkipUnsentStanza(); - } - - initiator->session->Terminate(); - initiator->ExpectSentStanza( - IqSet("7", kInitiator, kResponder, - TerminateXml(resulting_protocol, - cricket::STR_TERMINATE_SUCCESS))); - - responder->DeliverStanza(initiator->stanza()); - responder->ExpectSentStanza( - IqAck("7", kResponder, kInitiator)); - EXPECT_EQ(cricket::BaseSession::STATE_SENTTERMINATE, - initiator->session_state()); - EXPECT_EQ(cricket::BaseSession::STATE_RECEIVEDTERMINATE, - responder->session_state()); - } - - // Test an initiate with other content, called "main". - void TestOtherContent(SignalingProtocol initiator_protocol, - SignalingProtocol responder_protocol, - SignalingProtocol resulting_protocol) { - std::string content_name = "main"; - std::string content_type = "http://oink.splat/session"; - std::string content_name_a = content_name; - std::string channel_name_a = "rtp"; - std::string content_name_b = content_name; - std::string channel_name_b = "rtcp"; - std::string initiate_xml = InitiateXml( - initiator_protocol, - content_name_a, content_type); - std::string transport_info_a_xml = TransportInfo4Xml( - initiator_protocol, content_name, - channel_name_a, 0, 1, - channel_name_b, 2, 3); - std::string transport_info_b_xml = ""; - std::string transport_info_reply_a_xml = TransportInfo4Xml( - resulting_protocol, content_name, - channel_name_a, 4, 5, - channel_name_b, 6, 7); - std::string transport_info_reply_b_xml = ""; - std::string accept_xml = AcceptXml( - resulting_protocol, - content_name_a, content_type); - - - TestSession(initiator_protocol, responder_protocol, resulting_protocol, - content_type, - content_type, - content_name_a, channel_name_a, - content_name_b, channel_name_b, - initiate_xml, - transport_info_a_xml, transport_info_b_xml, - transport_info_reply_a_xml, transport_info_reply_b_xml, - accept_xml); - } - - // Test an initiate with audio content. - void TestAudioContent(SignalingProtocol initiator_protocol, - SignalingProtocol responder_protocol, - SignalingProtocol resulting_protocol) { - std::string gingle_content_type = cricket::NS_GINGLE_AUDIO; - std::string content_name = cricket::CN_AUDIO; - std::string content_type = cricket::NS_JINGLE_RTP; - std::string channel_name_a = "rtp"; - std::string channel_name_b = "rtcp"; - std::string initiate_xml = InitiateXml( - initiator_protocol, - gingle_content_type, - content_name, content_type, - "", ""); - std::string transport_info_a_xml = TransportInfo4Xml( - initiator_protocol, content_name, - channel_name_a, 0, 1, - channel_name_b, 2, 3); - std::string transport_info_b_xml = ""; - std::string transport_info_reply_a_xml = TransportInfo4Xml( - resulting_protocol, content_name, - channel_name_a, 4, 5, - channel_name_b, 6, 7); - std::string transport_info_reply_b_xml = ""; - std::string accept_xml = AcceptXml( - resulting_protocol, - gingle_content_type, - content_name, content_type, - "", ""); - - - TestSession(initiator_protocol, responder_protocol, resulting_protocol, - gingle_content_type, - content_type, - content_name, channel_name_a, - content_name, channel_name_b, - initiate_xml, - transport_info_a_xml, transport_info_b_xml, - transport_info_reply_a_xml, transport_info_reply_b_xml, - accept_xml); - } - - // Since media content is "split" into two contents (audio and - // video), we need to treat it special. - void TestVideoContents(SignalingProtocol initiator_protocol, - SignalingProtocol responder_protocol, - SignalingProtocol resulting_protocol) { - std::string content_type = cricket::NS_JINGLE_RTP; - std::string gingle_content_type = cricket::NS_GINGLE_VIDEO; - std::string content_name_a = cricket::CN_AUDIO; - std::string channel_name_a = "rtp"; - std::string content_name_b = cricket::CN_VIDEO; - std::string channel_name_b = "video_rtp"; - - std::string initiate_xml = InitiateXml( - initiator_protocol, - gingle_content_type, - content_name_a, content_type, - content_name_b, content_type); - std::string transport_info_a_xml = TransportInfo2Xml( - initiator_protocol, content_name_a, - channel_name_a, 0, 1); - std::string transport_info_b_xml = TransportInfo2Xml( - initiator_protocol, content_name_b, - channel_name_b, 2, 3); - std::string transport_info_reply_a_xml = TransportInfo2Xml( - resulting_protocol, content_name_a, - channel_name_a, 4, 5); - std::string transport_info_reply_b_xml = TransportInfo2Xml( - resulting_protocol, content_name_b, - channel_name_b, 6, 7); - std::string accept_xml = AcceptXml( - resulting_protocol, - gingle_content_type, - content_name_a, content_type, - content_name_b, content_type); - - TestSession(initiator_protocol, responder_protocol, resulting_protocol, - gingle_content_type, - content_type, - content_name_a, channel_name_a, - content_name_b, channel_name_b, - initiate_xml, - transport_info_a_xml, transport_info_b_xml, - transport_info_reply_a_xml, transport_info_reply_b_xml, - accept_xml); - } - - void TestBadRedirect(SignalingProtocol protocol) { - std::string content_name = "main"; - std::string content_type = "http://oink.splat/session"; - std::string channel_name_a = "chana"; - std::string channel_name_b = "chanb"; - std::string initiate_xml = InitiateXml( - protocol, content_name, content_type); - std::string transport_info_xml = TransportInfo4Xml( - protocol, content_name, - channel_name_a, 0, 1, - channel_name_b, 2, 3); - std::string transport_info_reply_xml = TransportInfo4Xml( - protocol, content_name, - channel_name_a, 4, 5, - channel_name_b, 6, 7); - std::string accept_xml = AcceptXml( - protocol, content_name, content_type); - std::string responder_full = kResponder + "/full"; - - rtc::scoped_ptr allocator( - new TestPortAllocator()); - int next_message_id = 0; - - rtc::scoped_ptr initiator( - new TestClient(allocator.get(), &next_message_id, - kInitiator, protocol, - content_type, - content_name, channel_name_a, - content_name, channel_name_b)); - - rtc::scoped_ptr responder( - new TestClient(allocator.get(), &next_message_id, - responder_full, protocol, - content_type, - content_name, channel_name_a, - content_name, channel_name_b)); - - // Create Session and check channels and state. - initiator->CreateSession(); - EXPECT_EQ(1U, initiator->session_created_count); - EXPECT_EQ(kSessionId, initiator->session->id()); - EXPECT_EQ(initiator->session->local_name(), kInitiator); - EXPECT_EQ(cricket::BaseSession::STATE_INIT, - initiator->session_state()); - - EXPECT_TRUE(initiator->HasChannel(content_name, 1)); - EXPECT_TRUE(initiator->HasChannel(content_name, 2)); - - // Initiate and expect initiate message sent. - cricket::SessionDescription* offer = NewTestSessionDescription( - content_name, content_type); - EXPECT_TRUE(initiator->session->Initiate(kResponder, offer)); - EXPECT_EQ(initiator->session->remote_name(), kResponder); - EXPECT_EQ(initiator->session->local_description(), offer); - - EXPECT_TRUE_WAIT(initiator->sent_stanza_count() > 0, kEventTimeout); - EXPECT_EQ(cricket::BaseSession::STATE_SENTINITIATE, - initiator->session_state()); - initiator->ExpectSentStanza( - IqSet("0", kInitiator, kResponder, initiate_xml)); - - // Expect transport-info message from initiator. - initiator->DeliverAckToLastStanza(); - initiator->PrepareCandidates(); - EXPECT_TRUE_WAIT(initiator->sent_stanza_count() > 0, kEventTimeout); - initiator->ExpectSentStanza( - IqSet("1", kInitiator, kResponder, transport_info_xml)); - - // Send an unauthorized redirect to the initiator and expect it be ignored. - initiator->blow_up_on_error = false; - const buzz::XmlElement* initiate_stanza = initiator->stanza(); - rtc::scoped_ptr redirect_stanza( - buzz::XmlElement::ForStr( - IqError("ER", kResponder, kInitiator, - RedirectXml(protocol, initiate_xml, "not@allowed.com")))); - initiator->session_manager->OnFailedSend( - initiate_stanza, redirect_stanza.get()); - EXPECT_EQ(initiator->session->remote_name(), kResponder); - initiator->blow_up_on_error = true; - EXPECT_EQ(initiator->error_count, 1); - } - - void TestGoodRedirect(SignalingProtocol protocol) { - std::string content_name = "main"; - std::string content_type = "http://oink.splat/session"; - std::string channel_name_a = "chana"; - std::string channel_name_b = "chanb"; - std::string initiate_xml = InitiateXml( - protocol, content_name, content_type); - std::string transport_info_xml = TransportInfo4Xml( - protocol, content_name, - channel_name_a, 0, 1, - channel_name_b, 2, 3); - std::string transport_info_reply_xml = TransportInfo4Xml( - protocol, content_name, - channel_name_a, 4, 5, - channel_name_b, 6, 7); - std::string accept_xml = AcceptXml( - protocol, content_name, content_type); - std::string responder_full = kResponder + "/full"; - - rtc::scoped_ptr allocator( - new TestPortAllocator()); - int next_message_id = 0; - - rtc::scoped_ptr initiator( - new TestClient(allocator.get(), &next_message_id, - kInitiator, protocol, - content_type, - content_name, channel_name_a, - content_name, channel_name_b)); - - rtc::scoped_ptr responder( - new TestClient(allocator.get(), &next_message_id, - responder_full, protocol, - content_type, - content_name, channel_name_a, - content_name, channel_name_b)); - - // Create Session and check channels and state. - initiator->CreateSession(); - EXPECT_EQ(1U, initiator->session_created_count); - EXPECT_EQ(kSessionId, initiator->session->id()); - EXPECT_EQ(initiator->session->local_name(), kInitiator); - EXPECT_EQ(cricket::BaseSession::STATE_INIT, - initiator->session_state()); - - EXPECT_TRUE(initiator->HasChannel(content_name, 1)); - EXPECT_TRUE(initiator->HasChannel(content_name, 2)); - - // Initiate and expect initiate message sent. - cricket::SessionDescription* offer = NewTestSessionDescription( - content_name, content_type); - EXPECT_TRUE(initiator->session->Initiate(kResponder, offer)); - EXPECT_EQ(initiator->session->remote_name(), kResponder); - EXPECT_EQ(initiator->session->local_description(), offer); - - EXPECT_TRUE_WAIT(initiator->sent_stanza_count() > 0, kEventTimeout); - EXPECT_EQ(cricket::BaseSession::STATE_SENTINITIATE, - initiator->session_state()); - initiator->ExpectSentStanza( - IqSet("0", kInitiator, kResponder, initiate_xml)); - - // Expect transport-info message from initiator. - initiator->DeliverAckToLastStanza(); - initiator->PrepareCandidates(); - EXPECT_TRUE_WAIT(initiator->sent_stanza_count() > 0, kEventTimeout); - initiator->ExpectSentStanza( - IqSet("1", kInitiator, kResponder, transport_info_xml)); - - // Send a redirect to the initiator and expect all of the message - // to be resent. - const buzz::XmlElement* initiate_stanza = initiator->stanza(); - rtc::scoped_ptr redirect_stanza( - buzz::XmlElement::ForStr( - IqError("ER2", kResponder, kInitiator, - RedirectXml(protocol, initiate_xml, responder_full)))); - initiator->session_manager->OnFailedSend( - initiate_stanza, redirect_stanza.get()); - EXPECT_EQ(initiator->session->remote_name(), responder_full); - - EXPECT_TRUE_WAIT(initiator->sent_stanza_count() > 0, kEventTimeout); - initiator->ExpectSentStanza( - IqSet("2", kInitiator, responder_full, initiate_xml)); - initiator->ExpectSentStanza( - IqSet("3", kInitiator, responder_full, transport_info_xml)); - - // Deliver the initiate. Expect ack and session created with - // transports. - responder->DeliverStanza( - IqSet("2", kInitiator, responder_full, initiate_xml)); - responder->ExpectSentStanza( - IqAck("2", responder_full, kInitiator)); - EXPECT_EQ(0U, responder->sent_stanza_count()); - - EXPECT_EQ(1U, responder->session_created_count); - EXPECT_EQ(kSessionId, responder->session->id()); - EXPECT_EQ(responder->session->local_name(), responder_full); - EXPECT_EQ(responder->session->remote_name(), kInitiator); - EXPECT_EQ(cricket::BaseSession::STATE_RECEIVEDINITIATE, - responder->session_state()); - - EXPECT_TRUE(responder->HasChannel(content_name, 1)); - EXPECT_TRUE(responder->HasChannel(content_name, 2)); - - // Deliver transport-info and expect ack. - responder->DeliverStanza( - IqSet("3", kInitiator, responder_full, transport_info_xml)); - responder->ExpectSentStanza( - IqAck("3", responder_full, kInitiator)); - - // Expect reply transport-infos sent to new remote JID - responder->PrepareCandidates(); - EXPECT_TRUE_WAIT(responder->sent_stanza_count() > 0, kEventTimeout); - responder->ExpectSentStanza( - IqSet("4", responder_full, kInitiator, transport_info_reply_xml)); - - initiator->DeliverStanza(responder->stanza()); - initiator->ExpectSentStanza( - IqAck("4", kInitiator, responder_full)); - - // The channels should be able to become writable at this point. This - // requires pinging, so it may take a little while. - EXPECT_TRUE_WAIT(initiator->chan_a->writable() && - initiator->chan_a->readable(), kEventTimeout); - EXPECT_TRUE_WAIT(initiator->chan_b->writable() && - initiator->chan_b->readable(), kEventTimeout); - EXPECT_TRUE_WAIT(responder->chan_a->writable() && - responder->chan_a->readable(), kEventTimeout); - EXPECT_TRUE_WAIT(responder->chan_b->writable() && - responder->chan_b->readable(), kEventTimeout); - - // Accept the session and expect accept stanza. - cricket::SessionDescription* answer = NewTestSessionDescription( - content_name, content_type); - EXPECT_TRUE(responder->session->Accept(answer)); - EXPECT_EQ(responder->session->local_description(), answer); - - responder->ExpectSentStanza( - IqSet("5", responder_full, kInitiator, accept_xml)); - EXPECT_EQ(0U, responder->sent_stanza_count()); - - // Deliver the accept message and expect an ack. - initiator->DeliverStanza(responder->stanza()); - EXPECT_TRUE_WAIT(initiator->sent_stanza_count() > 0, kEventTimeout); - initiator->ExpectSentStanza( - IqAck("5", kInitiator, responder_full)); - EXPECT_EQ(0U, initiator->sent_stanza_count()); - - // Both sessions should be in progress and have functioning - // channels. - EXPECT_EQ_WAIT(cricket::BaseSession::STATE_INPROGRESS, - initiator->session_state(), kEventTimeout); - EXPECT_EQ_WAIT(cricket::BaseSession::STATE_INPROGRESS, - responder->session_state(), kEventTimeout); - TestSendRecv(initiator->chan_a.get(), initiator->chan_b.get(), - responder->chan_a.get(), responder->chan_b.get()); - } - - void TestCandidatesInInitiateAndAccept(const std::string& test_name) { - std::string content_name = "main"; - std::string content_type = "http://oink.splat/session"; - std::string channel_name_a = "rtp"; - std::string channel_name_b = "rtcp"; - cricket::SignalingProtocol protocol = PROTOCOL_JINGLE; - - rtc::scoped_ptr allocator( - new TestPortAllocator()); - int next_message_id = 0; - - rtc::scoped_ptr initiator( - new TestClient(allocator.get(), &next_message_id, - kInitiator, protocol, - content_type, - content_name, channel_name_a, - content_name, channel_name_b)); - - rtc::scoped_ptr responder( - new TestClient(allocator.get(), &next_message_id, - kResponder, protocol, - content_type, - content_name, channel_name_a, - content_name, channel_name_b)); - - // Create Session and check channels and state. - initiator->CreateSession(); - EXPECT_TRUE(initiator->HasTransport(content_name)); - EXPECT_TRUE(initiator->HasChannel(content_name, 1)); - EXPECT_TRUE(initiator->HasTransport(content_name)); - EXPECT_TRUE(initiator->HasChannel(content_name, 2)); - - // Initiate and expect initiate message sent. - cricket::SessionDescription* offer = NewTestSessionDescription( - content_name, content_type); - EXPECT_TRUE(initiator->session->Initiate(kResponder, offer)); - - EXPECT_TRUE_WAIT(initiator->sent_stanza_count() > 0, kEventTimeout); - EXPECT_EQ(cricket::BaseSession::STATE_SENTINITIATE, - initiator->session_state()); - initiator->ExpectSentStanza( - IqSet("0", kInitiator, kResponder, - InitiateXml(protocol, content_name, content_type))); - - // Fake the delivery the initiate and candidates together. - responder->DeliverStanza( - IqSet("A", kInitiator, kResponder, - JingleInitiateActionXml( - JingleContentXml( - content_name, content_type, kTransportType, - P2pCandidateXml(channel_name_a, 0) + - P2pCandidateXml(channel_name_a, 1) + - P2pCandidateXml(channel_name_b, 2) + - P2pCandidateXml(channel_name_b, 3))))); - responder->ExpectSentStanza( - IqAck("A", kResponder, kInitiator)); - EXPECT_EQ(0U, responder->sent_stanza_count()); - - EXPECT_EQ(1U, responder->session_created_count); - EXPECT_EQ(kSessionId, responder->session->id()); - EXPECT_EQ(responder->session->local_name(), kResponder); - EXPECT_EQ(responder->session->remote_name(), kInitiator); - EXPECT_EQ(cricket::BaseSession::STATE_RECEIVEDINITIATE, - responder->session_state()); - - EXPECT_TRUE(responder->HasTransport(content_name)); - EXPECT_TRUE(responder->HasChannel(content_name, 1)); - EXPECT_TRUE(responder->HasTransport(content_name)); - EXPECT_TRUE(responder->HasChannel(content_name, 2)); - - // Expect transport-info message from initiator. - // But don't send candidates until initiate ack is received. - initiator->DeliverAckToLastStanza(); - initiator->PrepareCandidates(); - EXPECT_TRUE_WAIT(initiator->sent_stanza_count() > 0, kEventTimeout); - initiator->ExpectSentStanza( - IqSet("1", kInitiator, kResponder, - TransportInfo4Xml(protocol, content_name, - channel_name_a, 0, 1, - channel_name_b, 2, 3))); - - responder->PrepareCandidates(); - EXPECT_TRUE_WAIT(responder->sent_stanza_count() > 0, kEventTimeout); - responder->ExpectSentStanza( - IqSet("2", kResponder, kInitiator, - TransportInfo4Xml(protocol, content_name, - channel_name_a, 4, 5, - channel_name_b, 6, 7))); - - // Accept the session and expect accept stanza. - cricket::SessionDescription* answer = NewTestSessionDescription( - content_name, content_type); - EXPECT_TRUE(responder->session->Accept(answer)); - - responder->ExpectSentStanza( - IqSet("3", kResponder, kInitiator, - AcceptXml(protocol, content_name, content_type))); - EXPECT_EQ(0U, responder->sent_stanza_count()); - - // Fake the delivery the accept and candidates together. - initiator->DeliverStanza( - IqSet("B", kResponder, kInitiator, - JingleActionXml("session-accept", - JingleContentXml( - content_name, content_type, kTransportType, - P2pCandidateXml(channel_name_a, 4) + - P2pCandidateXml(channel_name_a, 5) + - P2pCandidateXml(channel_name_b, 6) + - P2pCandidateXml(channel_name_b, 7))))); - EXPECT_TRUE_WAIT(initiator->sent_stanza_count() > 0, kEventTimeout); - initiator->ExpectSentStanza( - IqAck("B", kInitiator, kResponder)); - EXPECT_EQ(0U, initiator->sent_stanza_count()); - - // The channels should be able to become writable at this point. This - // requires pinging, so it may take a little while. - EXPECT_TRUE_WAIT(initiator->chan_a->writable() && - initiator->chan_a->readable(), kEventTimeout); - EXPECT_TRUE_WAIT(initiator->chan_b->writable() && - initiator->chan_b->readable(), kEventTimeout); - EXPECT_TRUE_WAIT(responder->chan_a->writable() && - responder->chan_a->readable(), kEventTimeout); - EXPECT_TRUE_WAIT(responder->chan_b->writable() && - responder->chan_b->readable(), kEventTimeout); - - - // Both sessions should be in progress and have functioning - // channels. - EXPECT_EQ(protocol, initiator->session->current_protocol()); - EXPECT_EQ(protocol, responder->session->current_protocol()); - EXPECT_EQ_WAIT(cricket::BaseSession::STATE_INPROGRESS, - initiator->session_state(), kEventTimeout); - EXPECT_EQ_WAIT(cricket::BaseSession::STATE_INPROGRESS, - responder->session_state(), kEventTimeout); - TestSendRecv(initiator->chan_a.get(), initiator->chan_b.get(), - responder->chan_a.get(), responder->chan_b.get()); - } - - // Tests that when an initiator terminates right after initiate, - // everything behaves correctly. - void TestEarlyTerminationFromInitiator(SignalingProtocol protocol) { - std::string content_name = "main"; - std::string content_type = "http://oink.splat/session"; - - rtc::scoped_ptr allocator( - new TestPortAllocator()); - int next_message_id = 0; - - rtc::scoped_ptr initiator( - new TestClient(allocator.get(), &next_message_id, - kInitiator, protocol, - content_type, - content_name, "a", - content_name, "b")); - - rtc::scoped_ptr responder( - new TestClient(allocator.get(), &next_message_id, - kResponder, protocol, - content_type, - content_name, "a", - content_name, "b")); - - // Send initiate - initiator->CreateSession(); - EXPECT_TRUE(initiator->session->Initiate( - kResponder, NewTestSessionDescription(content_name, content_type))); - initiator->ExpectSentStanza( - IqSet("0", kInitiator, kResponder, - InitiateXml(protocol, content_name, content_type))); - EXPECT_EQ(cricket::BaseSession::STATE_SENTINITIATE, - initiator->session_state()); - - responder->DeliverStanza(initiator->stanza()); - responder->ExpectSentStanza( - IqAck("0", kResponder, kInitiator)); - EXPECT_EQ(cricket::BaseSession::STATE_RECEIVEDINITIATE, - responder->session_state()); - - initiator->session->TerminateWithReason(cricket::STR_TERMINATE_ERROR); - initiator->ExpectSentStanza( - IqSet("1", kInitiator, kResponder, - TerminateXml(protocol, cricket::STR_TERMINATE_ERROR))); - EXPECT_EQ(cricket::BaseSession::STATE_SENTTERMINATE, - initiator->session_state()); - - responder->DeliverStanza(initiator->stanza()); - responder->ExpectSentStanza( - IqAck("1", kResponder, kInitiator)); - EXPECT_EQ(cricket::BaseSession::STATE_RECEIVEDTERMINATE, - responder->session_state()); - } - - // Tests that when the responder rejects, everything behaves - // correctly. - void TestRejection(SignalingProtocol protocol) { - std::string content_name = "main"; - std::string content_type = "http://oink.splat/session"; - - rtc::scoped_ptr allocator( - new TestPortAllocator()); - int next_message_id = 0; - - rtc::scoped_ptr initiator( - new TestClient(allocator.get(), &next_message_id, - kInitiator, protocol, - content_type, - content_name, "a", - content_name, "b")); - - // Send initiate - initiator->CreateSession(); - EXPECT_TRUE(initiator->session->Initiate( - kResponder, NewTestSessionDescription(content_name, content_type))); - initiator->ExpectSentStanza( - IqSet("0", kInitiator, kResponder, - InitiateXml(protocol, content_name, content_type))); - EXPECT_EQ(cricket::BaseSession::STATE_SENTINITIATE, - initiator->session_state()); - - initiator->DeliverStanza( - IqSet("1", kResponder, kInitiator, - RejectXml(protocol, cricket::STR_TERMINATE_ERROR))); - initiator->ExpectSentStanza( - IqAck("1", kInitiator, kResponder)); - if (protocol == PROTOCOL_JINGLE) { - EXPECT_EQ(cricket::BaseSession::STATE_RECEIVEDTERMINATE, - initiator->session_state()); - } else { - EXPECT_EQ(cricket::BaseSession::STATE_RECEIVEDREJECT, - initiator->session_state()); - } - } - - void TestTransportMux() { - SignalingProtocol initiator_protocol = PROTOCOL_JINGLE; - SignalingProtocol responder_protocol = PROTOCOL_JINGLE; - SignalingProtocol resulting_protocol = PROTOCOL_JINGLE; - std::string content_type = cricket::NS_JINGLE_RTP; - std::string gingle_content_type = cricket::NS_GINGLE_VIDEO; - std::string content_name_a = cricket::CN_AUDIO; - std::string channel_name_a = "rtp"; - std::string content_name_b = cricket::CN_VIDEO; - std::string channel_name_b = "video_rtp"; - - std::string initiate_xml = InitiateXml( - initiator_protocol, - gingle_content_type, - content_name_a, content_type, - content_name_b, content_type, true); - std::string transport_info_a_xml = TransportInfo2Xml( - initiator_protocol, content_name_a, - channel_name_a, 0, 1); - std::string transport_info_b_xml = TransportInfo2Xml( - initiator_protocol, content_name_b, - channel_name_b, 2, 3); - std::string transport_info_reply_a_xml = TransportInfo2Xml( - resulting_protocol, content_name_a, - channel_name_a, 4, 5); - std::string transport_info_reply_b_xml = TransportInfo2Xml( - resulting_protocol, content_name_b, - channel_name_b, 6, 7); - std::string accept_xml = AcceptXml( - resulting_protocol, - gingle_content_type, - content_name_a, content_type, - content_name_b, content_type, true); - - TestSession(initiator_protocol, responder_protocol, resulting_protocol, - gingle_content_type, - content_type, - content_name_a, channel_name_a, - content_name_b, channel_name_b, - initiate_xml, - transport_info_a_xml, transport_info_b_xml, - transport_info_reply_a_xml, transport_info_reply_b_xml, - accept_xml, - true); - } - - void TestSendDescriptionInfo() { - rtc::scoped_ptr allocator( - new TestPortAllocator()); - int next_message_id = 0; - - std::string content_name = "content-name"; - std::string content_type = "content-type"; - rtc::scoped_ptr initiator( - new TestClient(allocator.get(), &next_message_id, - kInitiator, PROTOCOL_JINGLE, - content_type, - content_name, "", - "", "")); - - initiator->CreateSession(); - cricket::SessionDescription* offer = NewTestSessionDescription( - content_name, content_type); - std::string initiate_xml = InitiateXml( - PROTOCOL_JINGLE, content_name, content_type); - - cricket::ContentInfos contents; - TestContentDescription content(content_type, content_type); - contents.push_back( - cricket::ContentInfo(content_name, content_type, &content)); - std::string description_info_xml = JingleDescriptionInfoXml( - content_name, content_type); - - EXPECT_TRUE(initiator->session->Initiate(kResponder, offer)); - initiator->ExpectSentStanza( - IqSet("0", kInitiator, kResponder, initiate_xml)); - - EXPECT_TRUE(initiator->session->SendDescriptionInfoMessage(contents)); - initiator->ExpectSentStanza( - IqSet("1", kInitiator, kResponder, description_info_xml)); - } - - void DoTestSignalNewDescription( - TestClient* client, - cricket::BaseSession::State state, - cricket::ContentAction expected_content_action, - cricket::ContentSource expected_content_source) { - // Clean up before the new test. - client->new_local_description = false; - client->new_remote_description = false; - - client->SetSessionState(state); - EXPECT_EQ((expected_content_source == cricket::CS_LOCAL), - client->new_local_description); - EXPECT_EQ((expected_content_source == cricket::CS_REMOTE), - client->new_remote_description); - EXPECT_EQ(expected_content_action, client->last_content_action); - EXPECT_EQ(expected_content_source, client->last_content_source); - } - - void TestCallerSignalNewDescription() { - rtc::scoped_ptr allocator( - new TestPortAllocator()); - int next_message_id = 0; - - std::string content_name = "content-name"; - std::string content_type = "content-type"; - rtc::scoped_ptr initiator( - new TestClient(allocator.get(), &next_message_id, - kInitiator, PROTOCOL_JINGLE, - content_type, - content_name, "", - "", "")); - - initiator->CreateSession(); - - // send offer -> send update offer -> - // receive pr answer -> receive update pr answer -> - // receive answer - DoTestSignalNewDescription( - initiator.get(), cricket::BaseSession::STATE_SENTINITIATE, - cricket::CA_OFFER, cricket::CS_LOCAL); - - DoTestSignalNewDescription( - initiator.get(), cricket::BaseSession::STATE_SENTINITIATE, - cricket::CA_OFFER, cricket::CS_LOCAL); - - DoTestSignalNewDescription( - initiator.get(), cricket::BaseSession::STATE_RECEIVEDPRACCEPT, - cricket::CA_PRANSWER, cricket::CS_REMOTE); - - DoTestSignalNewDescription( - initiator.get(), cricket::BaseSession::STATE_RECEIVEDPRACCEPT, - cricket::CA_PRANSWER, cricket::CS_REMOTE); - - DoTestSignalNewDescription( - initiator.get(), cricket::BaseSession::STATE_RECEIVEDACCEPT, - cricket::CA_ANSWER, cricket::CS_REMOTE); - } - - void TestCalleeSignalNewDescription() { - rtc::scoped_ptr allocator( - new TestPortAllocator()); - int next_message_id = 0; - - std::string content_name = "content-name"; - std::string content_type = "content-type"; - rtc::scoped_ptr initiator( - new TestClient(allocator.get(), &next_message_id, - kInitiator, PROTOCOL_JINGLE, - content_type, - content_name, "", - "", "")); - - initiator->CreateSession(); - - // receive offer -> receive update offer -> - // send pr answer -> send update pr answer -> - // send answer - DoTestSignalNewDescription( - initiator.get(), cricket::BaseSession::STATE_RECEIVEDINITIATE, - cricket::CA_OFFER, cricket::CS_REMOTE); - - DoTestSignalNewDescription( - initiator.get(), cricket::BaseSession::STATE_RECEIVEDINITIATE, - cricket::CA_OFFER, cricket::CS_REMOTE); - - DoTestSignalNewDescription( - initiator.get(), cricket::BaseSession::STATE_SENTPRACCEPT, - cricket::CA_PRANSWER, cricket::CS_LOCAL); - - DoTestSignalNewDescription( - initiator.get(), cricket::BaseSession::STATE_SENTPRACCEPT, - cricket::CA_PRANSWER, cricket::CS_LOCAL); - - DoTestSignalNewDescription( - initiator.get(), cricket::BaseSession::STATE_SENTACCEPT, - cricket::CA_ANSWER, cricket::CS_LOCAL); - } - - void TestGetTransportStats() { - rtc::scoped_ptr allocator( - new TestPortAllocator()); - int next_message_id = 0; - - std::string content_name = "content-name"; - std::string content_type = "content-type"; - rtc::scoped_ptr initiator( - new TestClient(allocator.get(), &next_message_id, - kInitiator, PROTOCOL_JINGLE, - content_type, - content_name, "", - "", "")); - initiator->CreateSession(); - - cricket::SessionStats stats; - EXPECT_TRUE(initiator->session->GetStats(&stats)); - // At initiation, there are 2 transports. - EXPECT_EQ(2ul, stats.proxy_to_transport.size()); - EXPECT_EQ(2ul, stats.transport_stats.size()); - } -}; - -// For each of these, "X => Y = Z" means "if a client with protocol X -// initiates to a client with protocol Y, they end up speaking protocol Z. - -// Gingle => Gingle = Gingle (with other content) -TEST_F(SessionTest, GingleToGingleOtherContent) { - TestOtherContent(PROTOCOL_GINGLE, PROTOCOL_GINGLE, PROTOCOL_GINGLE); -} - -// Gingle => Gingle = Gingle (with audio content) -TEST_F(SessionTest, GingleToGingleAudioContent) { - TestAudioContent(PROTOCOL_GINGLE, PROTOCOL_GINGLE, PROTOCOL_GINGLE); -} - -// Gingle => Gingle = Gingle (with video contents) -TEST_F(SessionTest, GingleToGingleVideoContents) { - TestVideoContents(PROTOCOL_GINGLE, PROTOCOL_GINGLE, PROTOCOL_GINGLE); -} - -// Jingle => Jingle = Jingle (with other content) -TEST_F(SessionTest, JingleToJingleOtherContent) { - TestOtherContent(PROTOCOL_JINGLE, PROTOCOL_JINGLE, PROTOCOL_JINGLE); -} - -// Jingle => Jingle = Jingle (with audio content) -TEST_F(SessionTest, JingleToJingleAudioContent) { - TestAudioContent(PROTOCOL_JINGLE, PROTOCOL_JINGLE, PROTOCOL_JINGLE); -} - -// Jingle => Jingle = Jingle (with video contents) -TEST_F(SessionTest, JingleToJingleVideoContents) { - TestVideoContents(PROTOCOL_JINGLE, PROTOCOL_JINGLE, PROTOCOL_JINGLE); -} - -// Hybrid => Hybrid = Jingle (with other content) -TEST_F(SessionTest, HybridToHybridOtherContent) { - TestOtherContent(PROTOCOL_HYBRID, PROTOCOL_HYBRID, PROTOCOL_JINGLE); -} - -// Hybrid => Hybrid = Jingle (with audio content) -TEST_F(SessionTest, HybridToHybridAudioContent) { - TestAudioContent(PROTOCOL_HYBRID, PROTOCOL_HYBRID, PROTOCOL_JINGLE); -} - -// Hybrid => Hybrid = Jingle (with video contents) -TEST_F(SessionTest, HybridToHybridVideoContents) { - TestVideoContents(PROTOCOL_HYBRID, PROTOCOL_HYBRID, PROTOCOL_JINGLE); -} - -// Gingle => Hybrid = Gingle (with other content) -TEST_F(SessionTest, GingleToHybridOtherContent) { - TestOtherContent(PROTOCOL_GINGLE, PROTOCOL_HYBRID, PROTOCOL_GINGLE); -} - -// Gingle => Hybrid = Gingle (with audio content) -TEST_F(SessionTest, GingleToHybridAudioContent) { - TestAudioContent(PROTOCOL_GINGLE, PROTOCOL_HYBRID, PROTOCOL_GINGLE); -} - -// Gingle => Hybrid = Gingle (with video contents) -TEST_F(SessionTest, GingleToHybridVideoContents) { - TestVideoContents(PROTOCOL_GINGLE, PROTOCOL_HYBRID, PROTOCOL_GINGLE); -} - -// Jingle => Hybrid = Jingle (with other content) -TEST_F(SessionTest, JingleToHybridOtherContent) { - TestOtherContent(PROTOCOL_JINGLE, PROTOCOL_HYBRID, PROTOCOL_JINGLE); -} - -// Jingle => Hybrid = Jingle (with audio content) -TEST_F(SessionTest, JingleToHybridAudioContent) { - TestAudioContent(PROTOCOL_JINGLE, PROTOCOL_HYBRID, PROTOCOL_JINGLE); -} - -// Jingle => Hybrid = Jingle (with video contents) -TEST_F(SessionTest, JingleToHybridVideoContents) { - TestVideoContents(PROTOCOL_JINGLE, PROTOCOL_HYBRID, PROTOCOL_JINGLE); -} - -// Hybrid => Gingle = Gingle (with other content) -TEST_F(SessionTest, HybridToGingleOtherContent) { - TestOtherContent(PROTOCOL_HYBRID, PROTOCOL_GINGLE, PROTOCOL_GINGLE); -} - -// Hybrid => Gingle = Gingle (with audio content) -TEST_F(SessionTest, HybridToGingleAudioContent) { - TestAudioContent(PROTOCOL_HYBRID, PROTOCOL_GINGLE, PROTOCOL_GINGLE); -} - -// Hybrid => Gingle = Gingle (with video contents) -TEST_F(SessionTest, HybridToGingleVideoContents) { - TestVideoContents(PROTOCOL_HYBRID, PROTOCOL_GINGLE, PROTOCOL_GINGLE); -} - -// Hybrid => Jingle = Jingle (with other content) -TEST_F(SessionTest, HybridToJingleOtherContent) { - TestOtherContent(PROTOCOL_HYBRID, PROTOCOL_JINGLE, PROTOCOL_JINGLE); -} - -// Hybrid => Jingle = Jingle (with audio content) -TEST_F(SessionTest, HybridToJingleAudioContent) { - TestAudioContent(PROTOCOL_HYBRID, PROTOCOL_JINGLE, PROTOCOL_JINGLE); -} - -// Hybrid => Jingle = Jingle (with video contents) -TEST_F(SessionTest, HybridToJingleVideoContents) { - TestVideoContents(PROTOCOL_HYBRID, PROTOCOL_JINGLE, PROTOCOL_JINGLE); -} - -TEST_F(SessionTest, GingleEarlyTerminationFromInitiator) { - TestEarlyTerminationFromInitiator(PROTOCOL_GINGLE); -} - -TEST_F(SessionTest, JingleEarlyTerminationFromInitiator) { - TestEarlyTerminationFromInitiator(PROTOCOL_JINGLE); -} - -TEST_F(SessionTest, HybridEarlyTerminationFromInitiator) { - TestEarlyTerminationFromInitiator(PROTOCOL_HYBRID); -} - -TEST_F(SessionTest, GingleRejection) { - TestRejection(PROTOCOL_GINGLE); -} - -TEST_F(SessionTest, JingleRejection) { - TestRejection(PROTOCOL_JINGLE); -} - -TEST_F(SessionTest, GingleGoodRedirect) { - TestGoodRedirect(PROTOCOL_GINGLE); -} - -TEST_F(SessionTest, JingleGoodRedirect) { - TestGoodRedirect(PROTOCOL_JINGLE); -} - -TEST_F(SessionTest, GingleBadRedirect) { - TestBadRedirect(PROTOCOL_GINGLE); -} - -TEST_F(SessionTest, JingleBadRedirect) { - TestBadRedirect(PROTOCOL_JINGLE); -} - -TEST_F(SessionTest, TestCandidatesInInitiateAndAccept) { - TestCandidatesInInitiateAndAccept("Candidates in initiate/accept"); -} - -TEST_F(SessionTest, TestTransportMux) { - TestTransportMux(); -} - -TEST_F(SessionTest, TestSendDescriptionInfo) { - TestSendDescriptionInfo(); -} - -TEST_F(SessionTest, TestCallerSignalNewDescription) { - TestCallerSignalNewDescription(); -} - -TEST_F(SessionTest, TestCalleeSignalNewDescription) { - TestCalleeSignalNewDescription(); -} - -TEST_F(SessionTest, TestGetTransportStats) { - TestGetTransportStats(); -} diff --git a/webrtc/libjingle/session/sessionclient.h b/webrtc/libjingle/session/sessionclient.h deleted file mode 100644 index 1db4b6ee6..000000000 --- a/webrtc/libjingle/session/sessionclient.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright 2004 The WebRTC Project Authors. All rights reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#ifndef WEBRTC_P2P_BASE_SESSIONCLIENT_H_ -#define WEBRTC_P2P_BASE_SESSIONCLIENT_H_ - -#include "webrtc/libjingle/session/constants.h" -#include "webrtc/p2p/base/constants.h" - -namespace buzz { -class XmlElement; -} - -namespace cricket { - -struct ParseError; -struct WriteError; -class Session; -class ContentDescription; - -class ContentParser { - public: - virtual bool ParseContent(SignalingProtocol protocol, - const buzz::XmlElement* elem, - ContentDescription** content, - ParseError* error) = 0; - // If not IsWriteable, then a given content should be "skipped" when - // writing in the given protocol, as if it didn't exist. We assume - // most things are writeable. We do this to avoid strange cases - // like data contents in Gingle, which aren't writable. - virtual bool IsWritable(SignalingProtocol protocol, - const ContentDescription* content) { - return true; - } - virtual bool WriteContent(SignalingProtocol protocol, - const ContentDescription* content, - buzz::XmlElement** elem, - WriteError* error) = 0; - virtual ~ContentParser() {} -}; - -// A SessionClient exists in 1-1 relation with each session. The implementor -// of this interface is the one that understands *what* the two sides are -// trying to send to one another. The lower-level layers only know how to send -// data; they do not know what is being sent. -class SessionClient : public ContentParser { - public: - // Notifies the client of the creation / destruction of sessions of this type. - // - // IMPORTANT: The SessionClient, in its handling of OnSessionCreate, must - // create whatever channels are indicate in the description. This is because - // the remote client may already be attempting to connect those channels. If - // we do not create our channel right away, then connection may fail or be - // delayed. - virtual void OnSessionCreate(Session* session, bool received_initiate) = 0; - virtual void OnSessionDestroy(Session* session) = 0; - - virtual bool ParseContent(SignalingProtocol protocol, - const buzz::XmlElement* elem, - ContentDescription** content, - ParseError* error) = 0; - virtual bool WriteContent(SignalingProtocol protocol, - const ContentDescription* content, - buzz::XmlElement** elem, - WriteError* error) = 0; - protected: - // The SessionClient interface explicitly does not include destructor - virtual ~SessionClient() { } -}; - -} // namespace cricket - -#endif // WEBRTC_P2P_BASE_SESSIONCLIENT_H_ diff --git a/webrtc/libjingle/session/sessionmanager.cc b/webrtc/libjingle/session/sessionmanager.cc deleted file mode 100644 index 25948b25a..000000000 --- a/webrtc/libjingle/session/sessionmanager.cc +++ /dev/null @@ -1,1150 +0,0 @@ -/* - * Copyright 2004 The WebRTC Project Authors. All rights reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#include "webrtc/libjingle/session/sessionmanager.h" - -#include "webrtc/base/common.h" -#include "webrtc/base/helpers.h" -#include "webrtc/base/logging.h" -#include "webrtc/base/scoped_ptr.h" -#include "webrtc/base/stringencode.h" -#include "webrtc/libjingle/session/p2ptransportparser.h" -#include "webrtc/libjingle/session/sessionmessages.h" -#include "webrtc/libjingle/xmpp/constants.h" -#include "webrtc/libjingle/xmpp/jid.h" -#include "webrtc/p2p/base/constants.h" - -namespace cricket { - -bool BadMessage(const buzz::QName type, - const std::string& text, - MessageError* err) { - err->SetType(type); - err->SetText(text); - return false; -} - - -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(), - 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; - initiator_name_ = initiator_name; - transport_parser_ = new P2PTransportParser(); - client_ = client; - initiate_acked_ = false; - current_protocol_ = PROTOCOL_HYBRID; -} - -Session::~Session() { - delete transport_parser_; -} - -bool Session::Initiate(const std::string& to, - const SessionDescription* sdesc) { - ASSERT(signaling_thread()->IsCurrent()); - SessionError error; - - // Only from STATE_INIT - if (state() != STATE_INIT) - return false; - - // Setup for signaling. - set_remote_name(to); - set_local_description(sdesc); - if (!CreateTransportProxies(GetEmptyTransportInfos(sdesc->contents()), - &error)) { - LOG(LS_ERROR) << "Could not create transports: " << error.text; - return false; - } - - if (!SendInitiateMessage(sdesc, &error)) { - LOG(LS_ERROR) << "Could not send initiate message: " << error.text; - return false; - } - - // We need to connect transport proxy and impl here so that we can process - // the TransportDescriptions. - SpeculativelyConnectAllTransportChannels(); - - PushdownTransportDescription(CS_LOCAL, CA_OFFER, NULL); - SetState(Session::STATE_SENTINITIATE); - return true; -} - -bool Session::Accept(const SessionDescription* sdesc) { - ASSERT(signaling_thread()->IsCurrent()); - - // Only if just received initiate - if (state() != STATE_RECEIVEDINITIATE) - return false; - - // Setup for signaling. - set_local_description(sdesc); - - SessionError error; - if (!SendAcceptMessage(sdesc, &error)) { - LOG(LS_ERROR) << "Could not send accept message: " << error.text; - return false; - } - // TODO(juberti): Add BUNDLE support to transport-info messages. - PushdownTransportDescription(CS_LOCAL, CA_ANSWER, NULL); - MaybeEnableMuxingSupport(); // Enable transport channel mux if supported. - SetState(Session::STATE_SENTACCEPT); - return true; -} - -bool Session::Reject(const std::string& reason) { - 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) - return false; - - SessionError error; - if (!SendRejectMessage(reason, &error)) { - LOG(LS_ERROR) << "Could not send reject message: " << error.text; - return false; - } - - SetState(STATE_SENTREJECT); - return true; -} - -bool Session::TerminateWithReason(const std::string& reason) { - ASSERT(signaling_thread()->IsCurrent()); - - // Either side can terminate, at any time. - switch (state()) { - case STATE_SENTTERMINATE: - case STATE_RECEIVEDTERMINATE: - return false; - - case STATE_SENTREJECT: - case STATE_RECEIVEDREJECT: - // We don't need to send terminate if we sent or received a reject... - // it's implicit. - break; - - default: - SessionError error; - if (!SendTerminateMessage(reason, &error)) { - LOG(LS_ERROR) << "Could not send terminate message: " << error.text; - return false; - } - break; - } - - SetState(STATE_SENTTERMINATE); - return true; -} - -bool Session::SendInfoMessage(const XmlElements& elems, - const std::string& remote_name) { - ASSERT(signaling_thread()->IsCurrent()); - SessionError error; - if (!SendMessage(ACTION_SESSION_INFO, elems, remote_name, &error)) { - LOG(LS_ERROR) << "Could not send info message " << error.text; - return false; - } - return true; -} - -bool Session::SendDescriptionInfoMessage(const ContentInfos& contents) { - XmlElements elems; - WriteError write_error; - if (!WriteDescriptionInfo(current_protocol_, - contents, - GetContentParsers(), - &elems, &write_error)) { - LOG(LS_ERROR) << "Could not write description info message: " - << write_error.text; - return false; - } - SessionError error; - if (!SendMessage(ACTION_DESCRIPTION_INFO, elems, &error)) { - LOG(LS_ERROR) << "Could not send description info message: " - << error.text; - return false; - } - return true; -} - -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, - TransportDescription(transport_type(), - std::string(), - std::string()))); - } - return tinfos; -} - -bool Session::OnRemoteCandidates( - const TransportInfos& tinfos, ParseError* error) { - for (TransportInfos::const_iterator tinfo = tinfos.begin(); - tinfo != tinfos.end(); ++tinfo) { - std::string str_error; - if (!BaseSession::OnRemoteCandidates( - tinfo->content_name, tinfo->description.candidates, &str_error)) { - return BadParse(str_error, error); - } - } - return true; -} - -bool Session::CreateTransportProxies(const TransportInfos& tinfos, - SessionError* error) { - for (TransportInfos::const_iterator tinfo = tinfos.begin(); - tinfo != tinfos.end(); ++tinfo) { - if (tinfo->description.transport_type != transport_type()) { - error->SetText("No supported transport in offer."); - return false; - } - - GetOrCreateTransportProxy(tinfo->content_name); - } - return true; -} - -TransportParserMap Session::GetTransportParsers() { - TransportParserMap parsers; - parsers[transport_type()] = transport_parser_; - return parsers; -} - -CandidateTranslatorMap Session::GetCandidateTranslators() { - CandidateTranslatorMap translators; - // NOTE: This technique makes it impossible to parse G-ICE - // candidates in session-initiate messages because the channels - // aren't yet created at that point. Since we don't use candidates - // in session-initiate messages, we should be OK. Once we switch to - // ICE, this translation shouldn't be necessary. - for (TransportMap::const_iterator iter = transport_proxies().begin(); - iter != transport_proxies().end(); ++iter) { - translators[iter->first] = iter->second; - } - return translators; -} - -ContentParserMap Session::GetContentParsers() { - ContentParserMap parsers; - parsers[content_type()] = client_; - // We need to be able parse both RTP-based and SCTP-based Jingle - // with the same client. - if (content_type() == NS_JINGLE_RTP) { - parsers[NS_JINGLE_DRAFT_SCTP] = client_; - } - return parsers; -} - -void Session::OnTransportRequestSignaling(Transport* transport) { - ASSERT(signaling_thread()->IsCurrent()); - TransportProxy* transproxy = GetTransportProxy(transport); - ASSERT(transproxy != NULL); - if (transproxy) { - // Reset candidate allocation status for the transport proxy. - transproxy->set_candidates_allocated(false); - } - SignalRequestSignaling(this); -} - -void Session::OnTransportConnecting(Transport* transport) { - // This is an indication that we should begin watching the writability - // state of the transport. - OnTransportWritable(transport); -} - -void Session::OnTransportWritable(Transport* transport) { - 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); - if (transport->HasChannels() && !transport->writable()) { - signaling_thread()->PostDelayed( - session_manager_->session_timeout() * 1000, this, MSG_TIMEOUT); - } -} - -void Session::OnTransportProxyCandidatesReady(TransportProxy* transproxy, - const Candidates& candidates) { - ASSERT(signaling_thread()->IsCurrent()); - if (transproxy != NULL) { - 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 - // order, we can remove this case. - transproxy->AddUnsentCandidates(candidates); - } else { - if (!transproxy->negotiated()) { - transproxy->AddSentCandidates(candidates); - } - SessionError error; - if (!SendTransportInfoMessage(transproxy, candidates, &error)) { - LOG(LS_ERROR) << "Could not send transport info message: " - << error.text; - return; - } - } - } -} - -void Session::OnIncomingMessage(const SessionMessage& msg) { - ASSERT(signaling_thread()->IsCurrent()); - ASSERT(state() == STATE_INIT || msg.from == remote_name()); - - if (current_protocol_== PROTOCOL_HYBRID) { - if (msg.protocol == PROTOCOL_GINGLE) { - current_protocol_ = PROTOCOL_GINGLE; - } else { - current_protocol_ = PROTOCOL_JINGLE; - } - } - - bool valid = false; - MessageError error; - switch (msg.type) { - case ACTION_SESSION_INITIATE: - valid = OnInitiateMessage(msg, &error); - break; - case ACTION_SESSION_INFO: - valid = OnInfoMessage(msg); - break; - case ACTION_SESSION_ACCEPT: - valid = OnAcceptMessage(msg, &error); - break; - case ACTION_SESSION_REJECT: - valid = OnRejectMessage(msg, &error); - break; - case ACTION_SESSION_TERMINATE: - valid = OnTerminateMessage(msg, &error); - break; - case ACTION_TRANSPORT_INFO: - valid = OnTransportInfoMessage(msg, &error); - break; - case ACTION_TRANSPORT_ACCEPT: - valid = OnTransportAcceptMessage(msg, &error); - break; - case ACTION_DESCRIPTION_INFO: - valid = OnDescriptionInfoMessage(msg, &error); - break; - default: - valid = BadMessage(buzz::QN_STANZA_BAD_REQUEST, - "unknown session message type", - &error); - } - - if (valid) { - SendAcknowledgementMessage(msg.stanza); - } else { - SignalErrorMessage(this, msg.stanza, error.type, - "modify", error.text, NULL); - } -} - -void Session::OnIncomingResponse(const buzz::XmlElement* orig_stanza, - const buzz::XmlElement* response_stanza, - const SessionMessage& msg) { - ASSERT(signaling_thread()->IsCurrent()); - - if (msg.type == ACTION_SESSION_INITIATE) { - OnInitiateAcked(); - } -} - -void Session::OnInitiateAcked() { - // 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 - // order, we can remove this case. - if (!initiate_acked_) { - initiate_acked_ = true; - SessionError error; - SendAllUnsentTransportInfoMessages(&error); - } -} - -void Session::OnFailedSend(const buzz::XmlElement* orig_stanza, - const buzz::XmlElement* error_stanza) { - ASSERT(signaling_thread()->IsCurrent()); - - SessionMessage msg; - ParseError parse_error; - if (!ParseSessionMessage(orig_stanza, &msg, &parse_error)) { - LOG(LS_ERROR) << "Error parsing failed send: " << parse_error.text - << ":" << orig_stanza; - return; - } - - // If the error is a session redirect, call OnRedirectError, which will - // continue the session with a new remote JID. - SessionRedirect redirect; - if (FindSessionRedirect(error_stanza, &redirect)) { - SessionError error; - if (!OnRedirectError(redirect, &error)) { - // TODO: Should we send a message back? The standard - // says nothing about it. - std::ostringstream desc; - desc << "Failed to redirect: " << error.text; - LOG(LS_ERROR) << desc.str(); - SetError(ERROR_RESPONSE, desc.str()); - } - return; - } - - std::string error_type = "cancel"; - - const buzz::XmlElement* error = error_stanza->FirstNamed(buzz::QN_ERROR); - if (error) { - error_type = error->Attr(buzz::QN_TYPE); - - LOG(LS_ERROR) << "Session error:\n" << error->Str() << "\n" - << "in response to:\n" << orig_stanza->Str(); - } else { - // don't crash if is missing - LOG(LS_ERROR) << "Session error without element, ignoring"; - return; - } - - if (msg.type == ACTION_TRANSPORT_INFO) { - // Transport messages frequently generate errors because they are sent right - // when we detect a network failure. For that reason, we ignore such - // errors, because if we do not establish writability again, we will - // terminate anyway. The exceptions are transport-specific error tags, - // which we pass on to the respective transport. - } else if ((error_type != "continue") && (error_type != "wait")) { - // We do not set an error if the other side said it is okay to continue - // (possibly after waiting). These errors can be ignored. - SetError(ERROR_RESPONSE, ""); - } -} - -bool Session::OnInitiateMessage(const SessionMessage& msg, - MessageError* error) { - if (!CheckState(STATE_INIT, error)) - return false; - - SessionInitiate init; - if (!ParseSessionInitiate(msg.protocol, msg.action_elem, - GetContentParsers(), GetTransportParsers(), - GetCandidateTranslators(), - &init, error)) - return false; - - SessionError session_error; - if (!CreateTransportProxies(init.transports, &session_error)) { - return BadMessage(buzz::QN_STANZA_NOT_ACCEPTABLE, - session_error.text, error); - } - - set_remote_name(msg.from); - set_initiator_name(msg.initiator); - set_remote_description(new SessionDescription(init.ClearContents(), - init.transports, - init.groups)); - // Updating transport with TransportDescription. - PushdownTransportDescription(CS_REMOTE, CA_OFFER, NULL); - SetState(STATE_RECEIVEDINITIATE); - - // Users of Session may listen to state change and call Reject(). - if (state() != STATE_SENTREJECT) { - if (!OnRemoteCandidates(init.transports, error)) - return false; - - // TODO(juberti): Auto-generate and push down the local transport answer. - // This is necessary for trickling to work with RFC 5245 ICE. - } - return true; -} - -bool Session::OnAcceptMessage(const SessionMessage& msg, MessageError* error) { - if (!CheckState(STATE_SENTINITIATE, error)) - return false; - - SessionAccept accept; - if (!ParseSessionAccept(msg.protocol, msg.action_elem, - GetContentParsers(), GetTransportParsers(), - GetCandidateTranslators(), - &accept, error)) { - return false; - } - - // If we get an accept, we can assume the initiate has been - // received, even if we haven't gotten an IQ response. - OnInitiateAcked(); - - set_remote_description(new SessionDescription(accept.ClearContents(), - accept.transports, - accept.groups)); - // Updating transport with TransportDescription. - PushdownTransportDescription(CS_REMOTE, CA_ANSWER, NULL); - MaybeEnableMuxingSupport(); // Enable transport channel mux if supported. - SetState(STATE_RECEIVEDACCEPT); - - if (!OnRemoteCandidates(accept.transports, error)) - return false; - - return true; -} - -bool Session::OnRejectMessage(const SessionMessage& msg, MessageError* error) { - if (!CheckState(STATE_SENTINITIATE, error)) - return false; - - SetState(STATE_RECEIVEDREJECT); - return true; -} - -bool Session::OnInfoMessage(const SessionMessage& msg) { - SignalInfoMessage(this, msg.action_elem); - return true; -} - -bool Session::OnTerminateMessage(const SessionMessage& msg, - MessageError* error) { - SessionTerminate term; - if (!ParseSessionTerminate(msg.protocol, msg.action_elem, &term, error)) - return false; - - SignalReceivedTerminateReason(this, term.reason); - if (term.debug_reason != buzz::STR_EMPTY) { - LOG(LS_VERBOSE) << "Received error on call: " << term.debug_reason; - } - - SetState(STATE_RECEIVEDTERMINATE); - return true; -} - -bool Session::OnTransportInfoMessage(const SessionMessage& msg, - MessageError* error) { - TransportInfos tinfos; - if (!ParseTransportInfos(msg.protocol, msg.action_elem, - initiator_description()->contents(), - GetTransportParsers(), GetCandidateTranslators(), - &tinfos, error)) - return false; - - if (!OnRemoteCandidates(tinfos, error)) - return false; - - return true; -} - -bool Session::OnTransportAcceptMessage(const SessionMessage& msg, - MessageError* error) { - // TODO: Currently here only for compatibility with - // Gingle 1.1 clients (notably, Google Voice). - return true; -} - -bool Session::OnDescriptionInfoMessage(const SessionMessage& msg, - MessageError* error) { - if (!CheckState(STATE_INPROGRESS, error)) - return false; - - DescriptionInfo description_info; - if (!ParseDescriptionInfo(msg.protocol, msg.action_elem, - GetContentParsers(), GetTransportParsers(), - GetCandidateTranslators(), - &description_info, error)) { - return false; - } - - ContentInfos& updated_contents = description_info.contents; - - // TODO: Currently, reflector sends back - // video stream updates even for an audio-only call, which causes - // this to fail. Put this back once reflector is fixed. - // - // ContentInfos::iterator it; - // First, ensure all updates are valid before modifying remote_description_. - // for (it = updated_contents.begin(); it != updated_contents.end(); ++it) { - // if (remote_description()->GetContentByName(it->name) == NULL) { - // return false; - // } - // } - - // TODO: We used to replace contents from an update, but - // that no longer works with partial updates. We need to figure out - // a way to merge patial updates into contents. For now, users of - // Session should listen to SignalRemoteDescriptionUpdate and handle - // updates. They should not expect remote_description to be the - // latest value. - // - // for (it = updated_contents.begin(); it != updated_contents.end(); ++it) { - // remote_description()->RemoveContentByName(it->name); - // remote_description()->AddContent(it->name, it->type, it->description); - // } - // } - - SignalRemoteDescriptionUpdate(this, updated_contents); - return true; -} - -bool BareJidsEqual(const std::string& name1, - const std::string& name2) { - buzz::Jid jid1(name1); - buzz::Jid jid2(name2); - - return jid1.IsValid() && jid2.IsValid() && jid1.BareEquals(jid2); -} - -bool Session::OnRedirectError(const SessionRedirect& redirect, - SessionError* error) { - MessageError message_error; - if (!CheckState(STATE_SENTINITIATE, &message_error)) { - return BadWrite(message_error.text, error); - } - - 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. - set_remote_name(redirect.target); - return (SendInitiateMessage(local_description(), error) && - ResendAllTransportInfoMessages(error)); -} - -bool Session::CheckState(State expected, MessageError* error) { - if (state() != expected) { - // The server can deliver messages out of order/repeated for various - // reasons. For example, if the server does not recive our iq response, - // it could assume that the iq it sent was lost, and will then send - // it again. Ideally, we should implement reliable messaging with - // duplicate elimination. - return BadMessage(buzz::QN_STANZA_NOT_ALLOWED, - "message not allowed in current state", - error); - } - return true; -} - -void Session::SetError(Error error, const std::string& error_desc) { - BaseSession::SetError(error, error_desc); - if (error != ERROR_NONE) - signaling_thread()->Post(this, MSG_ERROR); -} - -void Session::OnMessage(rtc::Message* pmsg) { - // preserve this because BaseSession::OnMessage may modify it - 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); - break; - - default: - // Explicitly ignoring some states here. - break; - } - break; - } -} - -bool Session::SendInitiateMessage(const SessionDescription* sdesc, - SessionError* error) { - SessionInitiate init; - init.contents = sdesc->contents(); - init.transports = GetEmptyTransportInfos(init.contents); - init.groups = sdesc->groups(); - return SendMessage(ACTION_SESSION_INITIATE, init, error); -} - -bool Session::WriteSessionAction( - SignalingProtocol protocol, const SessionInitiate& init, - XmlElements* elems, WriteError* error) { - return WriteSessionInitiate(protocol, init.contents, init.transports, - GetContentParsers(), GetTransportParsers(), - GetCandidateTranslators(), init.groups, - elems, error); -} - -bool Session::SendAcceptMessage(const SessionDescription* sdesc, - SessionError* error) { - XmlElements elems; - if (!WriteSessionAccept(current_protocol_, - sdesc->contents(), - GetEmptyTransportInfos(sdesc->contents()), - GetContentParsers(), GetTransportParsers(), - GetCandidateTranslators(), sdesc->groups(), - &elems, error)) { - return false; - } - return SendMessage(ACTION_SESSION_ACCEPT, elems, error); -} - -bool Session::SendRejectMessage(const std::string& reason, - SessionError* error) { - SessionTerminate term(reason); - return SendMessage(ACTION_SESSION_REJECT, term, error); -} - -bool Session::SendTerminateMessage(const std::string& reason, - SessionError* error) { - SessionTerminate term(reason); - return SendMessage(ACTION_SESSION_TERMINATE, term, error); -} - -bool Session::WriteSessionAction(SignalingProtocol protocol, - const SessionTerminate& term, - XmlElements* elems, WriteError* error) { - WriteSessionTerminate(protocol, term, elems); - return true; -} - -bool Session::SendTransportInfoMessage(const TransportInfo& tinfo, - SessionError* error) { - return SendMessage(ACTION_TRANSPORT_INFO, tinfo, error); -} - -bool Session::SendTransportInfoMessage(const TransportProxy* transproxy, - const Candidates& candidates, - SessionError* error) { - return SendTransportInfoMessage(TransportInfo(transproxy->content_name(), - TransportDescription(transproxy->type(), std::vector(), - std::string(), std::string(), ICEMODE_FULL, - CONNECTIONROLE_NONE, NULL, candidates)), error); -} - -bool Session::WriteSessionAction(SignalingProtocol protocol, - const TransportInfo& tinfo, - XmlElements* elems, WriteError* error) { - TransportInfos tinfos; - tinfos.push_back(tinfo); - return WriteTransportInfos(protocol, tinfos, - GetTransportParsers(), GetCandidateTranslators(), - elems, error); -} - -bool Session::ResendAllTransportInfoMessages(SessionError* error) { - 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( - transproxy, transproxy->sent_candidates(), error)) { - LOG(LS_ERROR) << "Could not resend transport info messages: " - << error->text; - return false; - } - transproxy->ClearSentCandidates(); - } - } - return true; -} - -bool Session::SendAllUnsentTransportInfoMessages(SessionError* error) { - 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( - transproxy, transproxy->unsent_candidates(), error)) { - LOG(LS_ERROR) << "Could not send unsent transport info messages: " - << error->text; - return false; - } - transproxy->ClearUnsentCandidates(); - } - } - return true; -} - -bool Session::SendMessage(ActionType type, const XmlElements& action_elems, - SessionError* error) { - return SendMessage(type, action_elems, remote_name(), error); -} - -bool Session::SendMessage(ActionType type, const XmlElements& action_elems, - const std::string& remote_name, SessionError* error) { - rtc::scoped_ptr stanza( - new buzz::XmlElement(buzz::QN_IQ)); - - SessionMessage msg(current_protocol_, type, id(), initiator_name()); - msg.to = remote_name; - WriteSessionMessage(msg, action_elems, stanza.get()); - - SignalOutgoingMessage(this, stanza.get()); - return true; -} - -template -bool Session::SendMessage(ActionType type, const Action& action, - SessionError* error) { - rtc::scoped_ptr stanza( - new buzz::XmlElement(buzz::QN_IQ)); - if (!WriteActionMessage(type, action, stanza.get(), error)) - return false; - - SignalOutgoingMessage(this, stanza.get()); - return true; -} - -template -bool Session::WriteActionMessage(ActionType type, const Action& action, - buzz::XmlElement* stanza, - WriteError* error) { - if (current_protocol_ == PROTOCOL_HYBRID) { - if (!WriteActionMessage(PROTOCOL_JINGLE, type, action, stanza, error)) - return false; - if (!WriteActionMessage(PROTOCOL_GINGLE, type, action, stanza, error)) - return false; - } else { - if (!WriteActionMessage(current_protocol_, type, action, stanza, error)) - return false; - } - return true; -} - -template -bool Session::WriteActionMessage(SignalingProtocol protocol, - ActionType type, const Action& action, - buzz::XmlElement* stanza, WriteError* error) { - XmlElements action_elems; - if (!WriteSessionAction(protocol, action, &action_elems, error)) - return false; - - SessionMessage msg(protocol, type, id(), initiator_name()); - msg.to = remote_name(); - - WriteSessionMessage(msg, action_elems, stanza); - return true; -} - -void Session::SendAcknowledgementMessage(const buzz::XmlElement* stanza) { - rtc::scoped_ptr ack( - new buzz::XmlElement(buzz::QN_IQ)); - ack->SetAttr(buzz::QN_TO, remote_name()); - ack->SetAttr(buzz::QN_ID, stanza->Attr(buzz::QN_ID)); - ack->SetAttr(buzz::QN_TYPE, "result"); - - SignalOutgoingMessage(this, ack.get()); -} - -SessionManager::SessionManager(PortAllocator *allocator, - rtc::Thread *worker) { - allocator_ = allocator; - signaling_thread_ = rtc::Thread::Current(); - if (worker == NULL) { - worker_thread_ = rtc::Thread::Current(); - } else { - worker_thread_ = worker; - } - timeout_ = 50; -} - -SessionManager::~SessionManager() { - // Note: Session::Terminate occurs asynchronously, so it's too late to - // delete them now. They better be all gone. - ASSERT(session_map_.empty()); - // TerminateAll(); - SignalDestroyed(); -} - -void SessionManager::AddClient(const std::string& content_type, - SessionClient* client) { - ASSERT(client_map_.find(content_type) == client_map_.end()); - client_map_[content_type] = client; -} - -void SessionManager::RemoveClient(const std::string& content_type) { - ClientMap::iterator iter = client_map_.find(content_type); - ASSERT(iter != client_map_.end()); - client_map_.erase(iter); -} - -SessionClient* SessionManager::GetClient(const std::string& content_type) { - ClientMap::iterator iter = client_map_.find(content_type); - return (iter != client_map_.end()) ? iter->second : NULL; -} - -Session* SessionManager::CreateSession(const std::string& local_name, - const std::string& content_type) { - std::string id; - return CreateSession(id, local_name, content_type); -} - -Session* SessionManager::CreateSession(const std::string& id, - const std::string& local_name, - const std::string& content_type) { - std::string sid = - id.empty() ? rtc::ToString(rtc::CreateRandomId64()) : id; - return CreateSession(local_name, local_name, sid, content_type, false); -} - -Session* SessionManager::CreateSession( - const std::string& local_name, const std::string& initiator_name, - const std::string& sid, const std::string& content_type, - bool received_initiate) { - SessionClient* client = GetClient(content_type); - ASSERT(client != NULL); - - Session* session = new Session(this, local_name, initiator_name, - sid, content_type, client); - session->SetIdentity(transport_desc_factory_.identity()); - session_map_[session->id()] = session; - session->SignalRequestSignaling.connect( - this, &SessionManager::OnRequestSignaling); - session->SignalOutgoingMessage.connect( - this, &SessionManager::OnOutgoingMessage); - session->SignalErrorMessage.connect(this, &SessionManager::OnErrorMessage); - SignalSessionCreate(session, received_initiate); - session->client()->OnSessionCreate(session, received_initiate); - return session; -} - -void SessionManager::DestroySession(Session* session) { - if (session != NULL) { - SessionMap::iterator it = session_map_.find(session->id()); - if (it != session_map_.end()) { - SignalSessionDestroy(session); - session->client()->OnSessionDestroy(session); - session_map_.erase(it); - delete session; - } - } -} - -Session* SessionManager::GetSession(const std::string& sid) { - SessionMap::iterator it = session_map_.find(sid); - if (it != session_map_.end()) - return it->second; - return NULL; -} - -void SessionManager::TerminateAll() { - while (session_map_.begin() != session_map_.end()) { - Session* session = session_map_.begin()->second; - session->Terminate(); - } -} - -bool SessionManager::IsSessionMessage(const buzz::XmlElement* stanza) { - return cricket::IsSessionMessage(stanza); -} - -Session* SessionManager::FindSession(const std::string& sid, - const std::string& remote_name) { - SessionMap::iterator iter = session_map_.find(sid); - if (iter == session_map_.end()) - return NULL; - - Session* session = iter->second; - if (buzz::Jid(remote_name) != buzz::Jid(session->remote_name())) - return NULL; - - return session; -} - -void SessionManager::OnIncomingMessage(const buzz::XmlElement* stanza) { - SessionMessage msg; - ParseError error; - - if (!ParseSessionMessage(stanza, &msg, &error)) { - SendErrorMessage(stanza, buzz::QN_STANZA_BAD_REQUEST, "modify", - error.text, NULL); - return; - } - - Session* session = FindSession(msg.sid, msg.from); - if (session) { - session->OnIncomingMessage(msg); - return; - } - if (msg.type != ACTION_SESSION_INITIATE) { - SendErrorMessage(stanza, buzz::QN_STANZA_BAD_REQUEST, "modify", - "unknown session", NULL); - return; - } - - std::string content_type; - if (!ParseContentType(msg.protocol, msg.action_elem, - &content_type, &error)) { - SendErrorMessage(stanza, buzz::QN_STANZA_BAD_REQUEST, "modify", - error.text, NULL); - return; - } - - if (!GetClient(content_type)) { - SendErrorMessage(stanza, buzz::QN_STANZA_BAD_REQUEST, "modify", - "unknown content type: " + content_type, NULL); - return; - } - - session = CreateSession(msg.to, msg.initiator, msg.sid, - content_type, true); - session->OnIncomingMessage(msg); -} - -void SessionManager::OnIncomingResponse(const buzz::XmlElement* orig_stanza, - const buzz::XmlElement* response_stanza) { - if (orig_stanza == NULL || response_stanza == NULL) { - return; - } - - SessionMessage msg; - ParseError error; - if (!ParseSessionMessage(orig_stanza, &msg, &error)) { - LOG(LS_WARNING) << "Error parsing incoming response: " << error.text - << ":" << orig_stanza; - return; - } - - Session* session = FindSession(msg.sid, msg.to); - if (!session) { - // Also try the QN_FROM in the response stanza, in case we sent the request - // to a bare JID but got the response from a full JID. - std::string ack_from = response_stanza->Attr(buzz::QN_FROM); - session = FindSession(msg.sid, ack_from); - } - if (session) { - session->OnIncomingResponse(orig_stanza, response_stanza, msg); - } -} - -void SessionManager::OnFailedSend(const buzz::XmlElement* orig_stanza, - const buzz::XmlElement* error_stanza) { - SessionMessage msg; - ParseError error; - if (!ParseSessionMessage(orig_stanza, &msg, &error)) { - return; // TODO: log somewhere? - } - - Session* session = FindSession(msg.sid, msg.to); - if (session) { - rtc::scoped_ptr synthetic_error; - if (!error_stanza) { - // A failed send is semantically equivalent to an error response, so we - // can just turn the former into the latter. - synthetic_error.reset( - CreateErrorMessage(orig_stanza, buzz::QN_STANZA_ITEM_NOT_FOUND, - "cancel", "Recipient did not respond", NULL)); - error_stanza = synthetic_error.get(); - } - - session->OnFailedSend(orig_stanza, error_stanza); - } -} - -void SessionManager::SendErrorMessage(const buzz::XmlElement* stanza, - const buzz::QName& name, - const std::string& type, - const std::string& text, - const buzz::XmlElement* extra_info) { - rtc::scoped_ptr msg( - CreateErrorMessage(stanza, name, type, text, extra_info)); - SignalOutgoingMessage(this, msg.get()); -} - -buzz::XmlElement* SessionManager::CreateErrorMessage( - const buzz::XmlElement* stanza, - const buzz::QName& name, - const std::string& type, - const std::string& text, - const buzz::XmlElement* extra_info) { - buzz::XmlElement* iq = new buzz::XmlElement(buzz::QN_IQ); - iq->SetAttr(buzz::QN_TO, stanza->Attr(buzz::QN_FROM)); - iq->SetAttr(buzz::QN_ID, stanza->Attr(buzz::QN_ID)); - iq->SetAttr(buzz::QN_TYPE, "error"); - - CopyXmlChildren(stanza, iq); - - buzz::XmlElement* error = new buzz::XmlElement(buzz::QN_ERROR); - error->SetAttr(buzz::QN_TYPE, type); - iq->AddElement(error); - - // If the error name is not in the standard namespace, we have to first add - // some error from that namespace. - if (name.Namespace() != buzz::NS_STANZA) { - error->AddElement( - new buzz::XmlElement(buzz::QN_STANZA_UNDEFINED_CONDITION)); - } - error->AddElement(new buzz::XmlElement(name)); - - if (extra_info) - error->AddElement(new buzz::XmlElement(*extra_info)); - - if (text.size() > 0) { - // It's okay to always use English here. This text is for debugging - // purposes only. - buzz::XmlElement* text_elem = new buzz::XmlElement(buzz::QN_STANZA_TEXT); - text_elem->SetAttr(buzz::QN_XML_LANG, "en"); - text_elem->SetBodyText(text); - error->AddElement(text_elem); - } - - // TODO: Should we include error codes as well for SIP compatibility? - - return iq; -} - -void SessionManager::OnOutgoingMessage(Session* session, - const buzz::XmlElement* stanza) { - SignalOutgoingMessage(this, stanza); -} - -void SessionManager::OnErrorMessage(BaseSession* session, - const buzz::XmlElement* stanza, - const buzz::QName& name, - const std::string& type, - const std::string& text, - const buzz::XmlElement* extra_info) { - SendErrorMessage(stanza, name, type, text, extra_info); -} - -void SessionManager::OnSignalingReady() { - for (SessionMap::iterator it = session_map_.begin(); - it != session_map_.end(); - ++it) { - it->second->OnSignalingReady(); - } -} - -void SessionManager::OnRequestSignaling(Session* session) { - SignalRequestSignaling(); -} - -} // namespace cricket diff --git a/webrtc/libjingle/session/sessionmanager.h b/webrtc/libjingle/session/sessionmanager.h deleted file mode 100644 index ec5cd98aa..000000000 --- a/webrtc/libjingle/session/sessionmanager.h +++ /dev/null @@ -1,436 +0,0 @@ -/* - * Copyright 2004 The WebRTC Project Authors. All rights reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#ifndef WEBRTC_LIBJINGLE_SESSION_SESSIONMANAGER_H_ -#define WEBRTC_LIBJINGLE_SESSION_SESSIONMANAGER_H_ - -#include -#include -#include -#include - -#include "webrtc/base/sigslot.h" -#include "webrtc/base/thread.h" -#include "webrtc/libjingle/session/parsing.h" -#include "webrtc/libjingle/session/sessionclient.h" -#include "webrtc/libjingle/session/sessionmessages.h" -#include "webrtc/libjingle/xmllite/xmlelement.h" -#include "webrtc/libjingle/xmpp/constants.h" -#include "webrtc/p2p/base/portallocator.h" -#include "webrtc/p2p/base/session.h" -#include "webrtc/p2p/base/transportdescriptionfactory.h" - -namespace buzz { -class QName; -class XmlElement; -} - -namespace cricket { - -class BaseSession; -class SessionClient; -class SessionManager; - -// Used for errors that will send back a specific error message to the -// remote peer. We add "type" to the errors because it's needed for -// SignalErrorMessage. -struct MessageError : ParseError { - buzz::QName type; - - // if unset, assume type is a parse error - MessageError() : ParseError(), type(buzz::QN_STANZA_BAD_REQUEST) {} - - void SetType(const buzz::QName type) { - this->type = type; - } -}; - -// Used for errors that may be returned by public session methods that -// can fail. -// TODO: Use this error in Session::Initiate and -// Session::Accept. -struct SessionError : WriteError { -}; - -// 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. - const std::string& remote_name() const { return remote_name_; } - - // Set the JID of the other peer in this session. - // Typically the remote_name_ is set when the session is initiated. - // However, sometimes (e.g when a proxy is used) the peer name is - // known after the BaseSession has been initiated and it must be updated - // explicitly. - void set_remote_name(const std::string& name) { remote_name_ = name; } - - // Set the JID of the initiator of this session. Allows for the overriding - // of the initiator to be a third-party, eg. the MUC JID when creating p2p - // sessions. - void set_initiator_name(const std::string& name) { initiator_name_ = name; } - - // 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_; } - - void set_current_protocol(SignalingProtocol protocol) { - current_protocol_ = protocol; - } - - // Updates the error state, signaling if necessary. - virtual void SetError(Error error, const std::string& error_desc); - - // 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 SignalRequestSignaling; - void OnSignalingReady() { BaseSession::OnSignalingReady(); } - - // Takes ownership of session description. - // TODO: Add an error argument to pass back to the caller. - bool Initiate(const std::string& to, - const SessionDescription* sdesc); - - // When we receive an initiate, we create a session in the - // RECEIVEDINITIATE state and respond by accepting or rejecting. - // Takes ownership of session description. - // TODO: Add an error argument to pass back to the caller. - 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 SignalReceivedTerminateReason; - - // The two clients in the session may also send one another - // arbitrary XML messages, which are called "info" messages. Sending - // takes ownership of the given elements. The signal does not; the - // parent element will be deleted after the signal. - bool SendInfoMessage(const XmlElements& elems, - const std::string& remote_name); - bool SendDescriptionInfoMessage(const ContentInfos& contents); - sigslot::signal2 SignalInfoMessage; - - private: - // Creates or destroys a session. (These are called only SessionManager.) - 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); - ~Session(); - // For each transport info, create a transport proxy. Can fail for - // incompatible transport types. - bool CreateTransportProxies(const TransportInfos& tinfos, - SessionError* error); - 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; - - // Maps passed to serialization functions. - TransportParserMap GetTransportParsers(); - ContentParserMap GetContentParsers(); - CandidateTranslatorMap GetCandidateTranslators(); - - virtual void OnTransportRequestSignaling(Transport* transport); - virtual void OnTransportConnecting(Transport* transport); - virtual void OnTransportWritable(Transport* transport); - virtual void OnTransportProxyCandidatesReady(TransportProxy* proxy, - const Candidates& candidates); - virtual void OnMessage(rtc::Message *pmsg); - - // Send various kinds of session messages. - bool SendInitiateMessage(const SessionDescription* sdesc, - SessionError* error); - bool SendAcceptMessage(const SessionDescription* sdesc, SessionError* error); - bool SendRejectMessage(const std::string& reason, SessionError* error); - bool SendTerminateMessage(const std::string& reason, SessionError* error); - bool SendTransportInfoMessage(const TransportInfo& tinfo, - SessionError* error); - bool SendTransportInfoMessage(const TransportProxy* transproxy, - const Candidates& candidates, - SessionError* error); - - bool ResendAllTransportInfoMessages(SessionError* error); - bool SendAllUnsentTransportInfoMessages(SessionError* error); - - // All versions of SendMessage send a message of the given type to - // the other client. Can pass either a set of elements or an - // "action", which must have a WriteSessionAction method to go along - // with it. Sending with an action supports sending a "hybrid" - // message. Sending with elements must be sent as Jingle or Gingle. - - // When passing elems, must be either Jingle or Gingle protocol. - // Takes ownership of action_elems. - bool SendMessage(ActionType type, const XmlElements& action_elems, - SessionError* error); - // Sends a messge, but overrides the remote name. - bool SendMessage(ActionType type, const XmlElements& action_elems, - const std::string& remote_name, - SessionError* error); - // When passing an action, may be Hybrid protocol. - template - bool SendMessage(ActionType type, const Action& action, - SessionError* error); - - // Helper methods to write the session message stanza. - template - bool WriteActionMessage(ActionType type, const Action& action, - buzz::XmlElement* stanza, WriteError* error); - template - bool WriteActionMessage(SignalingProtocol protocol, - ActionType type, const Action& action, - buzz::XmlElement* stanza, WriteError* error); - - // Sending messages in hybrid form requires being able to write them - // on a per-protocol basis with a common method signature, which all - // of these have. - bool WriteSessionAction(SignalingProtocol protocol, - const SessionInitiate& init, - XmlElements* elems, WriteError* error); - bool WriteSessionAction(SignalingProtocol protocol, - const TransportInfo& tinfo, - XmlElements* elems, WriteError* error); - bool WriteSessionAction(SignalingProtocol protocol, - const SessionTerminate& term, - XmlElements* elems, WriteError* error); - - // Sends a message back to the other client indicating that we have received - // and accepted their message. - void SendAcknowledgementMessage(const buzz::XmlElement* stanza); - - // Once signaling is ready, the session will use this signal to request the - // sending of each message. When messages are received by the other client, - // they should be handed to OnIncomingMessage. - // (These are called only by SessionManager.) - sigslot::signal2 SignalOutgoingMessage; - void OnIncomingMessage(const SessionMessage& msg); - - void OnIncomingResponse(const buzz::XmlElement* orig_stanza, - const buzz::XmlElement* response_stanza, - const SessionMessage& msg); - void OnInitiateAcked(); - void OnFailedSend(const buzz::XmlElement* orig_stanza, - const buzz::XmlElement* error_stanza); - - // Invoked when an error is found in an incoming message. This is translated - // into the appropriate XMPP response by SessionManager. - sigslot::signal6 SignalErrorMessage; - - // Handlers for the various types of messages. These functions may take - // pointers to the whole stanza or to just the session element. - bool OnInitiateMessage(const SessionMessage& msg, MessageError* error); - bool OnAcceptMessage(const SessionMessage& msg, MessageError* error); - bool OnRejectMessage(const SessionMessage& msg, MessageError* error); - bool OnInfoMessage(const SessionMessage& msg); - bool OnTerminateMessage(const SessionMessage& msg, MessageError* error); - bool OnTransportInfoMessage(const SessionMessage& msg, MessageError* error); - bool OnTransportAcceptMessage(const SessionMessage& msg, MessageError* error); - bool OnDescriptionInfoMessage(const SessionMessage& msg, MessageError* error); - bool OnRedirectError(const SessionRedirect& redirect, SessionError* error); - - // Verifies that we are in the appropriate state to receive this message. - bool CheckState(State state, MessageError* error); - - SessionManager* session_manager_; - bool initiate_acked_; - std::string local_name_; - std::string initiator_name_; - std::string remote_name_; - SessionClient* client_; - TransportParser* transport_parser_; - // Keeps track of what protocol we are speaking. - SignalingProtocol current_protocol_; - - friend class SessionManager; // For access to constructor, destructor, - // and signaling related methods. -}; - -// SessionManager manages session instances. -class SessionManager : public sigslot::has_slots<> { - public: - SessionManager(PortAllocator *allocator, - rtc::Thread *worker_thread = NULL); - virtual ~SessionManager(); - - PortAllocator *port_allocator() const { return allocator_; } - rtc::Thread *worker_thread() const { return worker_thread_; } - rtc::Thread *signaling_thread() const { return signaling_thread_; } - - int session_timeout() const { return timeout_; } - void set_session_timeout(int timeout) { timeout_ = timeout; } - - // Set what transport protocol we want to default to. - void set_transport_protocol(TransportProtocol proto) { - transport_desc_factory_.set_protocol(proto); - } - - // Control use of DTLS. An identity must be supplied if DTLS is enabled. - void set_secure(SecurePolicy policy) { - transport_desc_factory_.set_secure(policy); - } - void set_identity(rtc::SSLIdentity* identity) { - transport_desc_factory_.set_identity(identity); - } - const TransportDescriptionFactory* transport_desc_factory() const { - return &transport_desc_factory_; - } - - // Registers support for the given client. If we receive an initiate - // describing a session of the given type, we will automatically create a - // Session object and notify this client. The client may then accept or - // reject the session. - void AddClient(const std::string& content_type, SessionClient* client); - void RemoveClient(const std::string& content_type); - SessionClient* GetClient(const std::string& content_type); - - // Creates a new session. The given name is the JID of the client on whose - // behalf we initiate the session. - Session *CreateSession(const std::string& local_name, - const std::string& content_type); - - Session *CreateSession(const std::string& id, - const std::string& local_name, - const std::string& content_type); - - // Destroys the given session. - void DestroySession(Session *session); - - // Returns the session with the given ID or NULL if none exists. - Session *GetSession(const std::string& sid); - - // Terminates all of the sessions created by this manager. - void TerminateAll(); - - // These are signaled whenever the set of existing sessions changes. - sigslot::signal2 SignalSessionCreate; - sigslot::signal1 SignalSessionDestroy; - - // Determines whether the given stanza is intended for some session. - bool IsSessionMessage(const buzz::XmlElement* stanza); - - // Given a sid, initiator, and remote_name, this finds the matching Session - Session* FindSession(const std::string& sid, - const std::string& remote_name); - - // Called when we receive a stanza for which IsSessionMessage is true. - void OnIncomingMessage(const buzz::XmlElement* stanza); - - // Called when we get a response to a message that we sent. - void OnIncomingResponse(const buzz::XmlElement* orig_stanza, - const buzz::XmlElement* response_stanza); - - // Called if an attempted to send times out or an error is returned. In the - // timeout case error_stanza will be NULL - void OnFailedSend(const buzz::XmlElement* orig_stanza, - const buzz::XmlElement* error_stanza); - - // Signalled each time a session generates a signaling message to send. - // Also signalled on errors, but with a NULL session. - sigslot::signal2 SignalOutgoingMessage; - - // Signaled before sessions try to send certain signaling messages. The - // client should call OnSignalingReady once it is safe to send them. These - // steps are taken so that we don't send signaling messages trying to - // re-establish the connectivity of a session when the client cannot send - // the messages (and would probably just drop them on the floor). - // - // Note: you can connect this directly to OnSignalingReady(), if a signalling - // check is not supported. - sigslot::signal0<> SignalRequestSignaling; - void OnSignalingReady(); - - // Signaled when this SessionManager is deleted. - sigslot::signal0<> SignalDestroyed; - - private: - typedef std::map SessionMap; - typedef std::map ClientMap; - - // Helper function for CreateSession. This is also invoked when we receive - // a message attempting to initiate a session with this client. - Session *CreateSession(const std::string& local_name, - const std::string& initiator, - const std::string& sid, - const std::string& content_type, - bool received_initiate); - - // Attempts to find a registered session type whose description appears as - // a child of the session element. Such a child should be present indicating - // the application they hope to initiate. - std::string FindClient(const buzz::XmlElement* session); - - // Sends a message back to the other client indicating that we found an error - // in the stanza they sent. name identifies the error, type is one of the - // standard XMPP types (cancel, continue, modify, auth, wait), and text is a - // description for debugging purposes. - void SendErrorMessage(const buzz::XmlElement* stanza, - const buzz::QName& name, - const std::string& type, - const std::string& text, - const buzz::XmlElement* extra_info); - - // Creates and returns an error message from the given components. The - // caller is responsible for deleting this. - buzz::XmlElement* CreateErrorMessage( - const buzz::XmlElement* stanza, - const buzz::QName& name, - const std::string& type, - const std::string& text, - const buzz::XmlElement* extra_info); - - // Called each time a session requests signaling. - void OnRequestSignaling(Session* session); - - // Called each time a session has an outgoing message. - void OnOutgoingMessage(Session* session, const buzz::XmlElement* stanza); - - // Called each time a session has an error to send. - void OnErrorMessage(BaseSession* session, - const buzz::XmlElement* stanza, - const buzz::QName& name, - const std::string& type, - const std::string& text, - const buzz::XmlElement* extra_info); - - PortAllocator *allocator_; - rtc::Thread *signaling_thread_; - rtc::Thread *worker_thread_; - int timeout_; - TransportDescriptionFactory transport_desc_factory_; - SessionMap session_map_; - ClientMap client_map_; -}; - -} // namespace cricket - -#endif // WEBRTC_LIBJINGLE_SESSION_SESSIONMANAGER_H_ diff --git a/webrtc/libjingle/session/sessionmanagertask.h b/webrtc/libjingle/session/sessionmanagertask.h deleted file mode 100644 index 3d865c0ea..000000000 --- a/webrtc/libjingle/session/sessionmanagertask.h +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright 2004 The WebRTC Project Authors. All rights reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#ifndef WEBRTC_LIBJINGLE_SESSION_SESSIONMANAGERTASK_H_ -#define WEBRTC_LIBJINGLE_SESSION_SESSIONMANAGERTASK_H_ - -#include "webrtc/libjingle/session/sessionmanager.h" -#include "webrtc/libjingle/session/sessionsendtask.h" -#include "webrtc/libjingle/xmpp/xmppengine.h" -#include "webrtc/libjingle/xmpp/xmpptask.h" - -namespace cricket { - -// This class handles sending and receiving XMPP messages on behalf of the -// SessionManager. The sending part is handed over to SessionSendTask. - -class SessionManagerTask : public buzz::XmppTask { - public: - SessionManagerTask(buzz::XmppTaskParentInterface* parent, - SessionManager* session_manager) - : buzz::XmppTask(parent, buzz::XmppEngine::HL_SINGLE), - session_manager_(session_manager) { - } - - ~SessionManagerTask() { - } - - // Turns on simple support for sending messages, using SessionSendTask. - void EnableOutgoingMessages() { - session_manager_->SignalOutgoingMessage.connect( - this, &SessionManagerTask::OnOutgoingMessage); - session_manager_->SignalRequestSignaling.connect( - session_manager_, &SessionManager::OnSignalingReady); - } - - virtual int ProcessStart() { - const buzz::XmlElement *stanza = NextStanza(); - if (stanza == NULL) - return STATE_BLOCKED; - session_manager_->OnIncomingMessage(stanza); - return STATE_START; - } - - protected: - virtual bool HandleStanza(const buzz::XmlElement *stanza) { - if (!session_manager_->IsSessionMessage(stanza)) - return false; - // Responses are handled by the SessionSendTask that sent the request. - //if (stanza->Attr(buzz::QN_TYPE) != buzz::STR_SET) - // return false; - QueueStanza(stanza); - return true; - } - - private: - void OnOutgoingMessage(SessionManager* manager, - const buzz::XmlElement* stanza) { - cricket::SessionSendTask* sender = - new cricket::SessionSendTask(parent_, session_manager_); - sender->Send(stanza); - sender->Start(); - } - - SessionManager* session_manager_; -}; - -} // namespace cricket - -#endif // WEBRTC_P2P_CLIENT_SESSIONMANAGERTASK_H_ diff --git a/webrtc/libjingle/session/sessionmessages.cc b/webrtc/libjingle/session/sessionmessages.cc deleted file mode 100644 index acc8afabc..000000000 --- a/webrtc/libjingle/session/sessionmessages.cc +++ /dev/null @@ -1,1132 +0,0 @@ -/* - * Copyright 2010 The WebRTC Project Authors. All rights reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#include "webrtc/libjingle/session/sessionmessages.h" - -#include -#include - -#include "webrtc/base/logging.h" -#include "webrtc/base/scoped_ptr.h" -#include "webrtc/base/stringutils.h" -#include "webrtc/libjingle/session/parsing.h" -#include "webrtc/libjingle/session/sessionclient.h" -#include "webrtc/libjingle/xmllite/xmlconstants.h" -#include "webrtc/libjingle/xmpp/constants.h" -#include "webrtc/p2p/base/constants.h" -#include "webrtc/p2p/base/p2ptransport.h" -#include "webrtc/p2p/base/sessiondescription.h" -#include "webrtc/p2p/base/transport.h" - -namespace cricket { - -ActionType ToActionType(const std::string& type) { - if (type == GINGLE_ACTION_INITIATE) - return ACTION_SESSION_INITIATE; - if (type == GINGLE_ACTION_INFO) - return ACTION_SESSION_INFO; - if (type == GINGLE_ACTION_ACCEPT) - return ACTION_SESSION_ACCEPT; - if (type == GINGLE_ACTION_REJECT) - return ACTION_SESSION_REJECT; - if (type == GINGLE_ACTION_TERMINATE) - return ACTION_SESSION_TERMINATE; - if (type == GINGLE_ACTION_CANDIDATES) - return ACTION_TRANSPORT_INFO; - if (type == JINGLE_ACTION_SESSION_INITIATE) - return ACTION_SESSION_INITIATE; - if (type == JINGLE_ACTION_TRANSPORT_INFO) - return ACTION_TRANSPORT_INFO; - if (type == JINGLE_ACTION_TRANSPORT_ACCEPT) - return ACTION_TRANSPORT_ACCEPT; - if (type == JINGLE_ACTION_SESSION_INFO) - return ACTION_SESSION_INFO; - if (type == JINGLE_ACTION_SESSION_ACCEPT) - return ACTION_SESSION_ACCEPT; - if (type == JINGLE_ACTION_SESSION_TERMINATE) - return ACTION_SESSION_TERMINATE; - if (type == JINGLE_ACTION_TRANSPORT_INFO) - return ACTION_TRANSPORT_INFO; - if (type == JINGLE_ACTION_TRANSPORT_ACCEPT) - return ACTION_TRANSPORT_ACCEPT; - if (type == JINGLE_ACTION_DESCRIPTION_INFO) - return ACTION_DESCRIPTION_INFO; - if (type == GINGLE_ACTION_UPDATE) - return ACTION_DESCRIPTION_INFO; - - return ACTION_UNKNOWN; -} - -std::string ToJingleString(ActionType type) { - switch (type) { - case ACTION_SESSION_INITIATE: - return JINGLE_ACTION_SESSION_INITIATE; - case ACTION_SESSION_INFO: - return JINGLE_ACTION_SESSION_INFO; - case ACTION_DESCRIPTION_INFO: - return JINGLE_ACTION_DESCRIPTION_INFO; - case ACTION_SESSION_ACCEPT: - return JINGLE_ACTION_SESSION_ACCEPT; - // Notice that reject and terminate both go to - // "session-terminate", but there is no "session-reject". - case ACTION_SESSION_REJECT: - case ACTION_SESSION_TERMINATE: - return JINGLE_ACTION_SESSION_TERMINATE; - case ACTION_TRANSPORT_INFO: - return JINGLE_ACTION_TRANSPORT_INFO; - case ACTION_TRANSPORT_ACCEPT: - return JINGLE_ACTION_TRANSPORT_ACCEPT; - default: - return ""; - } -} - -std::string ToGingleString(ActionType type) { - switch (type) { - case ACTION_SESSION_INITIATE: - return GINGLE_ACTION_INITIATE; - case ACTION_SESSION_INFO: - return GINGLE_ACTION_INFO; - case ACTION_SESSION_ACCEPT: - return GINGLE_ACTION_ACCEPT; - case ACTION_SESSION_REJECT: - return GINGLE_ACTION_REJECT; - case ACTION_SESSION_TERMINATE: - return GINGLE_ACTION_TERMINATE; - case ACTION_TRANSPORT_INFO: - return GINGLE_ACTION_CANDIDATES; - default: - return ""; - } -} - - -bool IsJingleMessage(const buzz::XmlElement* stanza) { - const buzz::XmlElement* jingle = stanza->FirstNamed(QN_JINGLE); - if (jingle == NULL) - return false; - - return (jingle->HasAttr(buzz::QN_ACTION) && jingle->HasAttr(QN_SID)); -} - -bool IsGingleMessage(const buzz::XmlElement* stanza) { - const buzz::XmlElement* session = stanza->FirstNamed(QN_GINGLE_SESSION); - if (session == NULL) - return false; - - return (session->HasAttr(buzz::QN_TYPE) && - session->HasAttr(buzz::QN_ID) && - session->HasAttr(QN_INITIATOR)); -} - -bool IsSessionMessage(const buzz::XmlElement* stanza) { - return (stanza->Name() == buzz::QN_IQ && - stanza->Attr(buzz::QN_TYPE) == buzz::STR_SET && - (IsJingleMessage(stanza) || - IsGingleMessage(stanza))); -} - -bool ParseGingleSessionMessage(const buzz::XmlElement* session, - SessionMessage* msg, - ParseError* error) { - msg->protocol = PROTOCOL_GINGLE; - std::string type_string = session->Attr(buzz::QN_TYPE); - msg->type = ToActionType(type_string); - msg->sid = session->Attr(buzz::QN_ID); - msg->initiator = session->Attr(QN_INITIATOR); - msg->action_elem = session; - - if (msg->type == ACTION_UNKNOWN) - return BadParse("unknown action: " + type_string, error); - - return true; -} - -bool ParseJingleSessionMessage(const buzz::XmlElement* jingle, - SessionMessage* msg, - ParseError* error) { - msg->protocol = PROTOCOL_JINGLE; - std::string type_string = jingle->Attr(buzz::QN_ACTION); - msg->type = ToActionType(type_string); - msg->sid = jingle->Attr(QN_SID); - msg->initiator = GetXmlAttr(jingle, QN_INITIATOR, buzz::STR_EMPTY); - msg->action_elem = jingle; - - if (msg->type == ACTION_UNKNOWN) - return BadParse("unknown action: " + type_string, error); - - return true; -} - -bool ParseHybridSessionMessage(const buzz::XmlElement* jingle, - SessionMessage* msg, - ParseError* error) { - if (!ParseJingleSessionMessage(jingle, msg, error)) - return false; - msg->protocol = PROTOCOL_HYBRID; - - return true; -} - -bool ParseSessionMessage(const buzz::XmlElement* stanza, - SessionMessage* msg, - ParseError* error) { - msg->id = stanza->Attr(buzz::QN_ID); - msg->from = stanza->Attr(buzz::QN_FROM); - msg->to = stanza->Attr(buzz::QN_TO); - msg->stanza = stanza; - - const buzz::XmlElement* jingle = stanza->FirstNamed(QN_JINGLE); - const buzz::XmlElement* session = stanza->FirstNamed(QN_GINGLE_SESSION); - if (jingle && session) - return ParseHybridSessionMessage(jingle, msg, error); - if (jingle != NULL) - return ParseJingleSessionMessage(jingle, msg, error); - if (session != NULL) - return ParseGingleSessionMessage(session, msg, error); - return false; -} - -buzz::XmlElement* WriteGingleAction(const SessionMessage& msg, - const XmlElements& action_elems) { - buzz::XmlElement* session = new buzz::XmlElement(QN_GINGLE_SESSION, true); - session->AddAttr(buzz::QN_TYPE, ToGingleString(msg.type)); - session->AddAttr(buzz::QN_ID, msg.sid); - session->AddAttr(QN_INITIATOR, msg.initiator); - AddXmlChildren(session, action_elems); - return session; -} - -buzz::XmlElement* WriteJingleAction(const SessionMessage& msg, - const XmlElements& action_elems) { - buzz::XmlElement* jingle = new buzz::XmlElement(QN_JINGLE, true); - jingle->AddAttr(buzz::QN_ACTION, ToJingleString(msg.type)); - jingle->AddAttr(QN_SID, msg.sid); - if (msg.type == ACTION_SESSION_INITIATE) { - jingle->AddAttr(QN_INITIATOR, msg.initiator); - } - AddXmlChildren(jingle, action_elems); - return jingle; -} - -void WriteSessionMessage(const SessionMessage& msg, - const XmlElements& action_elems, - buzz::XmlElement* stanza) { - stanza->SetAttr(buzz::QN_TO, msg.to); - stanza->SetAttr(buzz::QN_TYPE, buzz::STR_SET); - - if (msg.protocol == PROTOCOL_GINGLE) { - stanza->AddElement(WriteGingleAction(msg, action_elems)); - } else { - stanza->AddElement(WriteJingleAction(msg, action_elems)); - } -} - - -TransportParser* GetTransportParser(const TransportParserMap& trans_parsers, - const std::string& transport_type) { - TransportParserMap::const_iterator map = trans_parsers.find(transport_type); - if (map == trans_parsers.end()) { - return NULL; - } else { - return map->second; - } -} - -CandidateTranslator* GetCandidateTranslator( - const CandidateTranslatorMap& translators, - const std::string& content_name) { - CandidateTranslatorMap::const_iterator map = translators.find(content_name); - if (map == translators.end()) { - return NULL; - } else { - return map->second; - } -} - -bool GetParserAndTranslator(const TransportParserMap& trans_parsers, - const CandidateTranslatorMap& translators, - const std::string& transport_type, - const std::string& content_name, - TransportParser** parser, - CandidateTranslator** translator, - ParseError* error) { - *parser = GetTransportParser(trans_parsers, transport_type); - if (*parser == NULL) { - return BadParse("unknown transport type: " + transport_type, error); - } - // Not having a translator isn't fatal when parsing. If this is called for an - // initiate message, we won't have our proxies set up to do the translation. - // Fortunately, for the cases where translation is needed, candidates are - // never sent in initiates. - *translator = GetCandidateTranslator(translators, content_name); - return true; -} - -bool GetParserAndTranslator(const TransportParserMap& trans_parsers, - const CandidateTranslatorMap& translators, - const std::string& transport_type, - const std::string& content_name, - TransportParser** parser, - CandidateTranslator** translator, - WriteError* error) { - *parser = GetTransportParser(trans_parsers, transport_type); - if (*parser == NULL) { - return BadWrite("unknown transport type: " + transport_type, error); - } - *translator = GetCandidateTranslator(translators, content_name); - if (*translator == NULL) { - return BadWrite("unknown content name: " + content_name, error); - } - return true; -} - -bool ParseGingleCandidate(const buzz::XmlElement* candidate_elem, - const TransportParserMap& trans_parsers, - const CandidateTranslatorMap& translators, - const std::string& content_name, - Candidates* candidates, - ParseError* error) { - TransportParser* trans_parser; - CandidateTranslator* translator; - if (!GetParserAndTranslator(trans_parsers, translators, - NS_GINGLE_P2P, content_name, - &trans_parser, &translator, error)) - return false; - - Candidate candidate; - if (!trans_parser->ParseGingleCandidate( - candidate_elem, translator, &candidate, error)) { - return false; - } - - candidates->push_back(candidate); - return true; -} - -bool ParseGingleCandidates(const buzz::XmlElement* parent, - const TransportParserMap& trans_parsers, - const CandidateTranslatorMap& translators, - const std::string& content_name, - Candidates* candidates, - ParseError* error) { - for (const buzz::XmlElement* candidate_elem = parent->FirstElement(); - candidate_elem != NULL; - candidate_elem = candidate_elem->NextElement()) { - if (candidate_elem->Name().LocalPart() == LN_CANDIDATE) { - if (!ParseGingleCandidate(candidate_elem, trans_parsers, translators, - content_name, candidates, error)) { - return false; - } - } - } - return true; -} - -bool ParseGingleTransportInfos(const buzz::XmlElement* action_elem, - const ContentInfos& contents, - const TransportParserMap& trans_parsers, - const CandidateTranslatorMap& translators, - TransportInfos* tinfos, - ParseError* error) { - bool has_audio = FindContentInfoByName(contents, CN_AUDIO) != NULL; - bool has_video = FindContentInfoByName(contents, CN_VIDEO) != NULL; - - // If we don't have media, no need to separate the candidates. - if (!has_audio && !has_video) { - TransportInfo tinfo(CN_OTHER, - TransportDescription(NS_GINGLE_P2P, std::string(), std::string())); - if (!ParseGingleCandidates(action_elem, trans_parsers, translators, - CN_OTHER, &tinfo.description.candidates, - error)) { - return false; - } - - tinfos->push_back(tinfo); - return true; - } - - // If we have media, separate the candidates. - TransportInfo audio_tinfo( - CN_AUDIO, - TransportDescription(NS_GINGLE_P2P, std::string(), std::string())); - TransportInfo video_tinfo( - CN_VIDEO, - TransportDescription(NS_GINGLE_P2P, std::string(), std::string())); - for (const buzz::XmlElement* candidate_elem = action_elem->FirstElement(); - candidate_elem != NULL; - candidate_elem = candidate_elem->NextElement()) { - if (candidate_elem->Name().LocalPart() == LN_CANDIDATE) { - const std::string& channel_name = candidate_elem->Attr(buzz::QN_NAME); - if (has_audio && - (channel_name == GICE_CHANNEL_NAME_RTP || - channel_name == GICE_CHANNEL_NAME_RTCP)) { - if (!ParseGingleCandidate( - candidate_elem, trans_parsers, - translators, CN_AUDIO, - &audio_tinfo.description.candidates, error)) { - return false; - } - } else if (has_video && - (channel_name == GICE_CHANNEL_NAME_VIDEO_RTP || - channel_name == GICE_CHANNEL_NAME_VIDEO_RTCP)) { - if (!ParseGingleCandidate( - candidate_elem, trans_parsers, - translators, CN_VIDEO, - &video_tinfo.description.candidates, error)) { - return false; - } - } else { - return BadParse("Unknown channel name: " + channel_name, error); - } - } - } - - if (has_audio) { - tinfos->push_back(audio_tinfo); - } - if (has_video) { - tinfos->push_back(video_tinfo); - } - return true; -} - -bool ParseJingleTransportInfo(const buzz::XmlElement* trans_elem, - const std::string& content_name, - const TransportParserMap& trans_parsers, - const CandidateTranslatorMap& translators, - TransportInfo* tinfo, - ParseError* error) { - TransportParser* trans_parser; - CandidateTranslator* translator; - if (!GetParserAndTranslator(trans_parsers, translators, - trans_elem->Name().Namespace(), content_name, - &trans_parser, &translator, error)) - return false; - - TransportDescription tdesc; - if (!trans_parser->ParseTransportDescription(trans_elem, translator, - &tdesc, error)) - return false; - - *tinfo = TransportInfo(content_name, tdesc); - return true; -} - -bool ParseJingleTransportInfos(const buzz::XmlElement* jingle, - const ContentInfos& contents, - const TransportParserMap trans_parsers, - const CandidateTranslatorMap& translators, - TransportInfos* tinfos, - ParseError* error) { - for (const buzz::XmlElement* pair_elem - = jingle->FirstNamed(QN_JINGLE_CONTENT); - pair_elem != NULL; - pair_elem = pair_elem->NextNamed(QN_JINGLE_CONTENT)) { - std::string content_name; - if (!RequireXmlAttr(pair_elem, QN_JINGLE_CONTENT_NAME, - &content_name, error)) - return false; - - const ContentInfo* content = FindContentInfoByName(contents, content_name); - if (!content) - return BadParse("Unknown content name: " + content_name, error); - - const buzz::XmlElement* trans_elem; - if (!RequireXmlChild(pair_elem, LN_TRANSPORT, &trans_elem, error)) - return false; - - TransportInfo tinfo; - if (!ParseJingleTransportInfo(trans_elem, content->name, - trans_parsers, translators, - &tinfo, error)) - return false; - - tinfos->push_back(tinfo); - } - - return true; -} - -buzz::XmlElement* NewTransportElement(const std::string& name) { - return new buzz::XmlElement(buzz::QName(name, LN_TRANSPORT), true); -} - -bool WriteGingleCandidates(const Candidates& candidates, - const TransportParserMap& trans_parsers, - const std::string& transport_type, - const CandidateTranslatorMap& translators, - const std::string& content_name, - XmlElements* elems, - WriteError* error) { - TransportParser* trans_parser; - CandidateTranslator* translator; - if (!GetParserAndTranslator(trans_parsers, translators, - transport_type, content_name, - &trans_parser, &translator, error)) - return false; - - for (size_t i = 0; i < candidates.size(); ++i) { - rtc::scoped_ptr element; - if (!trans_parser->WriteGingleCandidate(candidates[i], translator, - element.accept(), error)) { - return false; - } - - elems->push_back(element.release()); - } - - return true; -} - -bool WriteGingleTransportInfos(const TransportInfos& tinfos, - const TransportParserMap& trans_parsers, - const CandidateTranslatorMap& translators, - XmlElements* elems, - WriteError* error) { - for (TransportInfos::const_iterator tinfo = tinfos.begin(); - tinfo != tinfos.end(); ++tinfo) { - if (!WriteGingleCandidates(tinfo->description.candidates, - trans_parsers, tinfo->description.transport_type, - translators, tinfo->content_name, - elems, error)) - return false; - } - - return true; -} - -bool WriteJingleTransportInfo(const TransportInfo& tinfo, - const TransportParserMap& trans_parsers, - const CandidateTranslatorMap& translators, - XmlElements* elems, - WriteError* error) { - std::string transport_type = tinfo.description.transport_type; - TransportParser* trans_parser; - CandidateTranslator* translator; - if (!GetParserAndTranslator(trans_parsers, translators, - transport_type, tinfo.content_name, - &trans_parser, &translator, error)) - return false; - - buzz::XmlElement* trans_elem; - if (!trans_parser->WriteTransportDescription(tinfo.description, translator, - &trans_elem, error)) { - return false; - } - - elems->push_back(trans_elem); - return true; -} - -void WriteJingleContent(const std::string name, - const XmlElements& child_elems, - XmlElements* elems) { - buzz::XmlElement* content_elem = new buzz::XmlElement(QN_JINGLE_CONTENT); - content_elem->SetAttr(QN_JINGLE_CONTENT_NAME, name); - content_elem->SetAttr(QN_CREATOR, LN_INITIATOR); - AddXmlChildren(content_elem, child_elems); - - elems->push_back(content_elem); -} - -bool WriteJingleTransportInfos(const TransportInfos& tinfos, - const TransportParserMap& trans_parsers, - const CandidateTranslatorMap& translators, - XmlElements* elems, - WriteError* error) { - for (TransportInfos::const_iterator tinfo = tinfos.begin(); - tinfo != tinfos.end(); ++tinfo) { - XmlElements content_child_elems; - if (!WriteJingleTransportInfo(*tinfo, trans_parsers, translators, - &content_child_elems, error)) - - return false; - - WriteJingleContent(tinfo->content_name, content_child_elems, elems); - } - - return true; -} - -ContentParser* GetContentParser(const ContentParserMap& content_parsers, - const std::string& type) { - ContentParserMap::const_iterator map = content_parsers.find(type); - if (map == content_parsers.end()) { - return NULL; - } else { - return map->second; - } -} - -bool ParseContentInfo(SignalingProtocol protocol, - const std::string& name, - const std::string& type, - const buzz::XmlElement* elem, - const ContentParserMap& parsers, - ContentInfos* contents, - ParseError* error) { - ContentParser* parser = GetContentParser(parsers, type); - if (parser == NULL) - return BadParse("unknown application content: " + type, error); - - ContentDescription* desc; - if (!parser->ParseContent(protocol, elem, &desc, error)) - return false; - - contents->push_back(ContentInfo(name, type, desc)); - return true; -} - -bool ParseContentType(const buzz::XmlElement* parent_elem, - std::string* content_type, - const buzz::XmlElement** content_elem, - ParseError* error) { - if (!RequireXmlChild(parent_elem, LN_DESCRIPTION, content_elem, error)) - return false; - - *content_type = (*content_elem)->Name().Namespace(); - return true; -} - -bool ParseGingleContentInfos(const buzz::XmlElement* session, - const ContentParserMap& content_parsers, - ContentInfos* contents, - ParseError* error) { - std::string content_type; - const buzz::XmlElement* content_elem; - if (!ParseContentType(session, &content_type, &content_elem, error)) - return false; - - if (content_type == NS_GINGLE_VIDEO) { - // A parser parsing audio or video content should look at the - // namespace and only parse the codecs relevant to that namespace. - // We use this to control which codecs get parsed: first audio, - // then video. - rtc::scoped_ptr audio_elem( - new buzz::XmlElement(QN_GINGLE_AUDIO_CONTENT)); - CopyXmlChildren(content_elem, audio_elem.get()); - if (!ParseContentInfo(PROTOCOL_GINGLE, CN_AUDIO, NS_JINGLE_RTP, - audio_elem.get(), content_parsers, - contents, error)) - return false; - - if (!ParseContentInfo(PROTOCOL_GINGLE, CN_VIDEO, NS_JINGLE_RTP, - content_elem, content_parsers, - contents, error)) - return false; - } else if (content_type == NS_GINGLE_AUDIO) { - if (!ParseContentInfo(PROTOCOL_GINGLE, CN_AUDIO, NS_JINGLE_RTP, - content_elem, content_parsers, - contents, error)) - return false; - } else { - if (!ParseContentInfo(PROTOCOL_GINGLE, CN_OTHER, content_type, - content_elem, content_parsers, - contents, error)) - return false; - } - return true; -} - -bool ParseJingleContentInfos(const buzz::XmlElement* jingle, - const ContentParserMap& content_parsers, - ContentInfos* contents, - ParseError* error) { - for (const buzz::XmlElement* pair_elem - = jingle->FirstNamed(QN_JINGLE_CONTENT); - pair_elem != NULL; - pair_elem = pair_elem->NextNamed(QN_JINGLE_CONTENT)) { - std::string content_name; - if (!RequireXmlAttr(pair_elem, QN_JINGLE_CONTENT_NAME, - &content_name, error)) - return false; - - std::string content_type; - const buzz::XmlElement* content_elem; - if (!ParseContentType(pair_elem, &content_type, &content_elem, error)) - return false; - - if (!ParseContentInfo(PROTOCOL_JINGLE, content_name, content_type, - content_elem, content_parsers, - contents, error)) - return false; - } - return true; -} - -bool ParseJingleGroupInfos(const buzz::XmlElement* jingle, - ContentGroups* groups, - ParseError* error) { - for (const buzz::XmlElement* pair_elem - = jingle->FirstNamed(QN_JINGLE_DRAFT_GROUP); - pair_elem != NULL; - pair_elem = pair_elem->NextNamed(QN_JINGLE_DRAFT_GROUP)) { - std::string group_name; - if (!RequireXmlAttr(pair_elem, QN_JINGLE_DRAFT_GROUP_TYPE, - &group_name, error)) - return false; - - ContentGroup group(group_name); - for (const buzz::XmlElement* child_elem - = pair_elem->FirstNamed(QN_JINGLE_CONTENT); - child_elem != NULL; - child_elem = child_elem->NextNamed(QN_JINGLE_CONTENT)) { - std::string content_name; - if (!RequireXmlAttr(child_elem, QN_JINGLE_CONTENT_NAME, - &content_name, error)) - return false; - group.AddContentName(content_name); - } - groups->push_back(group); - } - return true; -} - -buzz::XmlElement* WriteContentInfo(SignalingProtocol protocol, - const ContentInfo& content, - const ContentParserMap& parsers, - WriteError* error) { - ContentParser* parser = GetContentParser(parsers, content.type); - if (parser == NULL) { - BadWrite("unknown content type: " + content.type, error); - return NULL; - } - - buzz::XmlElement* elem = NULL; - if (!parser->WriteContent(protocol, content.description, &elem, error)) - return NULL; - - return elem; -} - -bool IsWritable(SignalingProtocol protocol, - const ContentInfo& content, - const ContentParserMap& parsers) { - ContentParser* parser = GetContentParser(parsers, content.type); - if (parser == NULL) { - return false; - } - - return parser->IsWritable(protocol, content.description); -} - -bool WriteGingleContentInfos(const ContentInfos& contents, - const ContentParserMap& parsers, - XmlElements* elems, - WriteError* error) { - if (contents.size() == 1 || - (contents.size() == 2 && - !IsWritable(PROTOCOL_GINGLE, contents.at(1), parsers))) { - if (contents.front().rejected) { - return BadWrite("Gingle protocol may not reject individual contents.", - error); - } - buzz::XmlElement* elem = WriteContentInfo( - PROTOCOL_GINGLE, contents.front(), parsers, error); - if (!elem) - return false; - - elems->push_back(elem); - } else if (contents.size() >= 2 && - contents.at(0).type == NS_JINGLE_RTP && - contents.at(1).type == NS_JINGLE_RTP) { - // Special-case audio + video contents so that they are "merged" - // into one "video" content. - if (contents.at(0).rejected || contents.at(1).rejected) { - return BadWrite("Gingle protocol may not reject individual contents.", - error); - } - buzz::XmlElement* audio = WriteContentInfo( - PROTOCOL_GINGLE, contents.at(0), parsers, error); - if (!audio) - return false; - - buzz::XmlElement* video = WriteContentInfo( - PROTOCOL_GINGLE, contents.at(1), parsers, error); - if (!video) { - delete audio; - return false; - } - - CopyXmlChildren(audio, video); - elems->push_back(video); - delete audio; - } else { - return BadWrite("Gingle protocol may only have one content.", error); - } - - return true; -} - -const TransportInfo* GetTransportInfoByContentName( - const TransportInfos& tinfos, const std::string& content_name) { - for (TransportInfos::const_iterator tinfo = tinfos.begin(); - tinfo != tinfos.end(); ++tinfo) { - if (content_name == tinfo->content_name) { - return &*tinfo; - } - } - return NULL; -} - -bool WriteJingleContents(const ContentInfos& contents, - const ContentParserMap& content_parsers, - const TransportInfos& tinfos, - const TransportParserMap& trans_parsers, - const CandidateTranslatorMap& translators, - XmlElements* elems, - WriteError* error) { - for (ContentInfos::const_iterator content = contents.begin(); - content != contents.end(); ++content) { - if (content->rejected) { - continue; - } - const TransportInfo* tinfo = - GetTransportInfoByContentName(tinfos, content->name); - if (!tinfo) - return BadWrite("No transport for content: " + content->name, error); - - XmlElements pair_elems; - buzz::XmlElement* elem = WriteContentInfo( - PROTOCOL_JINGLE, *content, content_parsers, error); - if (!elem) - return false; - pair_elems.push_back(elem); - - if (!WriteJingleTransportInfo(*tinfo, trans_parsers, translators, - &pair_elems, error)) - return false; - - WriteJingleContent(content->name, pair_elems, elems); - } - return true; -} - -bool WriteJingleContentInfos(const ContentInfos& contents, - const ContentParserMap& content_parsers, - XmlElements* elems, - WriteError* error) { - for (ContentInfos::const_iterator content = contents.begin(); - content != contents.end(); ++content) { - if (content->rejected) { - continue; - } - XmlElements content_child_elems; - buzz::XmlElement* elem = WriteContentInfo( - PROTOCOL_JINGLE, *content, content_parsers, error); - if (!elem) - return false; - content_child_elems.push_back(elem); - WriteJingleContent(content->name, content_child_elems, elems); - } - return true; -} - -bool WriteJingleGroupInfo(const ContentInfos& contents, - const ContentGroups& groups, - XmlElements* elems, - WriteError* error) { - if (!groups.empty()) { - buzz::XmlElement* pair_elem = new buzz::XmlElement(QN_JINGLE_DRAFT_GROUP); - pair_elem->SetAttr(QN_JINGLE_DRAFT_GROUP_TYPE, GROUP_TYPE_BUNDLE); - - XmlElements pair_elems; - for (ContentInfos::const_iterator content = contents.begin(); - content != contents.end(); ++content) { - buzz::XmlElement* child_elem = - new buzz::XmlElement(QN_JINGLE_CONTENT, false); - child_elem->SetAttr(QN_JINGLE_CONTENT_NAME, content->name); - pair_elems.push_back(child_elem); - } - AddXmlChildren(pair_elem, pair_elems); - elems->push_back(pair_elem); - } - return true; -} - -bool ParseContentType(SignalingProtocol protocol, - const buzz::XmlElement* action_elem, - std::string* content_type, - ParseError* error) { - const buzz::XmlElement* content_elem; - if (protocol == PROTOCOL_GINGLE) { - if (!ParseContentType(action_elem, content_type, &content_elem, error)) - return false; - - // Internally, we only use NS_JINGLE_RTP. - if (*content_type == NS_GINGLE_AUDIO || - *content_type == NS_GINGLE_VIDEO) - *content_type = NS_JINGLE_RTP; - } else { - const buzz::XmlElement* pair_elem - = action_elem->FirstNamed(QN_JINGLE_CONTENT); - if (pair_elem == NULL) - return BadParse("No contents found", error); - - if (!ParseContentType(pair_elem, content_type, &content_elem, error)) - return false; - } - - return true; -} - -static bool ParseContentMessage( - SignalingProtocol protocol, - const buzz::XmlElement* action_elem, - bool expect_transports, - const ContentParserMap& content_parsers, - const TransportParserMap& trans_parsers, - const CandidateTranslatorMap& translators, - SessionInitiate* init, - ParseError* error) { - init->owns_contents = true; - if (protocol == PROTOCOL_GINGLE) { - if (!ParseGingleContentInfos(action_elem, content_parsers, - &init->contents, error)) - return false; - - if (expect_transports && - !ParseGingleTransportInfos(action_elem, init->contents, - trans_parsers, translators, - &init->transports, error)) - return false; - } else { - if (!ParseJingleContentInfos(action_elem, content_parsers, - &init->contents, error)) - return false; - if (!ParseJingleGroupInfos(action_elem, &init->groups, error)) - return false; - - if (expect_transports && - !ParseJingleTransportInfos(action_elem, init->contents, - trans_parsers, translators, - &init->transports, error)) - return false; - } - - return true; -} - -static bool WriteContentMessage( - SignalingProtocol protocol, - const ContentInfos& contents, - const TransportInfos& tinfos, - const ContentParserMap& content_parsers, - const TransportParserMap& transport_parsers, - const CandidateTranslatorMap& translators, - const ContentGroups& groups, - XmlElements* elems, - WriteError* error) { - if (protocol == PROTOCOL_GINGLE) { - if (!WriteGingleContentInfos(contents, content_parsers, elems, error)) - return false; - - if (!WriteGingleTransportInfos(tinfos, transport_parsers, translators, - elems, error)) - return false; - } else { - if (!WriteJingleContents(contents, content_parsers, - tinfos, transport_parsers, translators, - elems, error)) - return false; - if (!WriteJingleGroupInfo(contents, groups, elems, error)) - return false; - } - - return true; -} - -bool ParseSessionInitiate(SignalingProtocol protocol, - const buzz::XmlElement* action_elem, - const ContentParserMap& content_parsers, - const TransportParserMap& trans_parsers, - const CandidateTranslatorMap& translators, - SessionInitiate* init, - ParseError* error) { - bool expect_transports = true; - return ParseContentMessage(protocol, action_elem, expect_transports, - content_parsers, trans_parsers, translators, - init, error); -} - - -bool WriteSessionInitiate(SignalingProtocol protocol, - const ContentInfos& contents, - const TransportInfos& tinfos, - const ContentParserMap& content_parsers, - const TransportParserMap& transport_parsers, - const CandidateTranslatorMap& translators, - const ContentGroups& groups, - XmlElements* elems, - WriteError* error) { - return WriteContentMessage(protocol, contents, tinfos, - content_parsers, transport_parsers, translators, - groups, - elems, error); -} - -bool ParseSessionAccept(SignalingProtocol protocol, - const buzz::XmlElement* action_elem, - const ContentParserMap& content_parsers, - const TransportParserMap& transport_parsers, - const CandidateTranslatorMap& translators, - SessionAccept* accept, - ParseError* error) { - bool expect_transports = true; - return ParseContentMessage(protocol, action_elem, expect_transports, - content_parsers, transport_parsers, translators, - accept, error); -} - -bool WriteSessionAccept(SignalingProtocol protocol, - const ContentInfos& contents, - const TransportInfos& tinfos, - const ContentParserMap& content_parsers, - const TransportParserMap& transport_parsers, - const CandidateTranslatorMap& translators, - const ContentGroups& groups, - XmlElements* elems, - WriteError* error) { - return WriteContentMessage(protocol, contents, tinfos, - content_parsers, transport_parsers, translators, - groups, - elems, error); -} - -bool ParseSessionTerminate(SignalingProtocol protocol, - const buzz::XmlElement* action_elem, - SessionTerminate* term, - ParseError* error) { - if (protocol == PROTOCOL_GINGLE) { - const buzz::XmlElement* reason_elem = action_elem->FirstElement(); - if (reason_elem != NULL) { - term->reason = reason_elem->Name().LocalPart(); - const buzz::XmlElement *debug_elem = reason_elem->FirstElement(); - if (debug_elem != NULL) { - term->debug_reason = debug_elem->Name().LocalPart(); - } - } - return true; - } else { - const buzz::XmlElement* reason_elem = - action_elem->FirstNamed(QN_JINGLE_REASON); - if (reason_elem) { - reason_elem = reason_elem->FirstElement(); - if (reason_elem) { - term->reason = reason_elem->Name().LocalPart(); - } - } - return true; - } -} - -void WriteSessionTerminate(SignalingProtocol protocol, - const SessionTerminate& term, - XmlElements* elems) { - if (protocol == PROTOCOL_GINGLE) { - elems->push_back(new buzz::XmlElement(buzz::QName(NS_GINGLE, term.reason))); - } else { - if (!term.reason.empty()) { - buzz::XmlElement* reason_elem = new buzz::XmlElement(QN_JINGLE_REASON); - reason_elem->AddElement(new buzz::XmlElement( - buzz::QName(NS_JINGLE, term.reason))); - elems->push_back(reason_elem); - } - } -} - -bool ParseDescriptionInfo(SignalingProtocol protocol, - const buzz::XmlElement* action_elem, - const ContentParserMap& content_parsers, - const TransportParserMap& transport_parsers, - const CandidateTranslatorMap& translators, - DescriptionInfo* description_info, - ParseError* error) { - bool expect_transports = false; - return ParseContentMessage(protocol, action_elem, expect_transports, - content_parsers, transport_parsers, translators, - description_info, error); -} - -bool WriteDescriptionInfo(SignalingProtocol protocol, - const ContentInfos& contents, - const ContentParserMap& content_parsers, - XmlElements* elems, - WriteError* error) { - if (protocol == PROTOCOL_GINGLE) { - return WriteGingleContentInfos(contents, content_parsers, elems, error); - } else { - return WriteJingleContentInfos(contents, content_parsers, elems, error); - } -} - -bool ParseTransportInfos(SignalingProtocol protocol, - const buzz::XmlElement* action_elem, - const ContentInfos& contents, - const TransportParserMap& trans_parsers, - const CandidateTranslatorMap& translators, - TransportInfos* tinfos, - ParseError* error) { - if (protocol == PROTOCOL_GINGLE) { - return ParseGingleTransportInfos( - action_elem, contents, trans_parsers, translators, tinfos, error); - } else { - return ParseJingleTransportInfos( - action_elem, contents, trans_parsers, translators, tinfos, error); - } -} - -bool WriteTransportInfos(SignalingProtocol protocol, - const TransportInfos& tinfos, - const TransportParserMap& trans_parsers, - const CandidateTranslatorMap& translators, - XmlElements* elems, - WriteError* error) { - if (protocol == PROTOCOL_GINGLE) { - return WriteGingleTransportInfos(tinfos, trans_parsers, translators, - elems, error); - } else { - return WriteJingleTransportInfos(tinfos, trans_parsers, translators, - elems, error); - } -} - -bool GetUriTarget(const std::string& prefix, const std::string& str, - std::string* after) { - size_t pos = str.find(prefix); - if (pos == std::string::npos) - return false; - - *after = str.substr(pos + prefix.size(), std::string::npos); - return true; -} - -bool FindSessionRedirect(const buzz::XmlElement* stanza, - SessionRedirect* redirect) { - const buzz::XmlElement* error_elem = GetXmlChild(stanza, LN_ERROR); - if (error_elem == NULL) - return false; - - const buzz::XmlElement* redirect_elem = - error_elem->FirstNamed(QN_GINGLE_REDIRECT); - if (redirect_elem == NULL) - redirect_elem = error_elem->FirstNamed(buzz::QN_STANZA_REDIRECT); - if (redirect_elem == NULL) - return false; - - if (!GetUriTarget(STR_REDIRECT_PREFIX, redirect_elem->BodyText(), - &redirect->target)) - return false; - - return true; -} - -} // namespace cricket diff --git a/webrtc/libjingle/session/sessionmessages.h b/webrtc/libjingle/session/sessionmessages.h deleted file mode 100644 index 49c5f5346..000000000 --- a/webrtc/libjingle/session/sessionmessages.h +++ /dev/null @@ -1,219 +0,0 @@ -/* - * Copyright 2010 The WebRTC Project Authors. All rights reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#ifndef WEBRTC_LIBJINGLE_SESSION_SESSIONMESSAGES_H_ -#define WEBRTC_LIBJINGLE_SESSION_SESSIONMESSAGES_H_ - -#include -#include -#include - -#include "webrtc/base/basictypes.h" -#include "webrtc/libjingle/session/constants.h" -#include "webrtc/libjingle/session/parsing.h" -#include "webrtc/libjingle/session/transportparser.h" -#include "webrtc/libjingle/xmllite/xmlelement.h" -#include "webrtc/p2p/base/candidate.h" -#include "webrtc/p2p/base/constants.h" -#include "webrtc/p2p/base/sessiondescription.h" // Needed to delete contents. -#include "webrtc/p2p/base/transport.h" -#include "webrtc/p2p/base/transportinfo.h" - -namespace cricket { - -struct ParseError; -struct WriteError; -class Candidate; -class ContentParser; -class TransportParser; - -typedef std::vector Candidates; -typedef std::map ContentParserMap; -typedef std::map TransportParserMap; - -enum ActionType { - ACTION_UNKNOWN, - - ACTION_SESSION_INITIATE, - ACTION_SESSION_INFO, - ACTION_SESSION_ACCEPT, - ACTION_SESSION_REJECT, - ACTION_SESSION_TERMINATE, - - ACTION_TRANSPORT_INFO, - ACTION_TRANSPORT_ACCEPT, - - ACTION_DESCRIPTION_INFO, -}; - -// Abstraction of a element within an stanza, per XMPP -// standard XEP-166. Can be serialized into multiple protocols, -// including the standard (Jingle) and the draft standard (Gingle). -// In general, used to communicate actions related to a p2p session, -// such accept, initiate, terminate, etc. - -struct SessionMessage { - SessionMessage() : action_elem(NULL), stanza(NULL) {} - - SessionMessage(SignalingProtocol protocol, ActionType type, - const std::string& sid, const std::string& initiator) : - protocol(protocol), type(type), sid(sid), initiator(initiator), - action_elem(NULL), stanza(NULL) {} - - std::string id; - std::string from; - std::string to; - SignalingProtocol protocol; - ActionType type; - std::string sid; // session id - std::string initiator; - - // Used for further parsing when necessary. - // Represents or . - const buzz::XmlElement* action_elem; - // Mostly used for debugging. - const buzz::XmlElement* stanza; -}; - -// TODO: Break up this class so we don't have to typedef it into -// different classes. -struct ContentMessage { - ContentMessage() : owns_contents(false) {} - - ~ContentMessage() { - if (owns_contents) { - for (ContentInfos::iterator content = contents.begin(); - content != contents.end(); content++) { - delete content->description; - } - } - } - - // Caller takes ownership of contents. - ContentInfos ClearContents() { - ContentInfos out; - contents.swap(out); - owns_contents = false; - return out; - } - - bool owns_contents; - ContentInfos contents; - TransportInfos transports; - ContentGroups groups; -}; - -typedef ContentMessage SessionInitiate; -typedef ContentMessage SessionAccept; -// Note that a DescriptionInfo does not have TransportInfos. -typedef ContentMessage DescriptionInfo; - -struct SessionTerminate { - SessionTerminate() {} - - explicit SessionTerminate(const std::string& reason) : - reason(reason) {} - - std::string reason; - std::string debug_reason; -}; - -struct SessionRedirect { - std::string target; -}; - -// Content name => translator -typedef std::map CandidateTranslatorMap; - -bool IsSessionMessage(const buzz::XmlElement* stanza); -bool ParseSessionMessage(const buzz::XmlElement* stanza, - SessionMessage* msg, - ParseError* error); -// Will return an error if there is more than one content type. -bool ParseContentType(SignalingProtocol protocol, - const buzz::XmlElement* action_elem, - std::string* content_type, - ParseError* error); -void WriteSessionMessage(const SessionMessage& msg, - const XmlElements& action_elems, - buzz::XmlElement* stanza); -bool ParseSessionInitiate(SignalingProtocol protocol, - const buzz::XmlElement* action_elem, - const ContentParserMap& content_parsers, - const TransportParserMap& transport_parsers, - const CandidateTranslatorMap& translators, - SessionInitiate* init, - ParseError* error); -bool WriteSessionInitiate(SignalingProtocol protocol, - const ContentInfos& contents, - const TransportInfos& tinfos, - const ContentParserMap& content_parsers, - const TransportParserMap& transport_parsers, - const CandidateTranslatorMap& translators, - const ContentGroups& groups, - XmlElements* elems, - WriteError* error); -bool ParseSessionAccept(SignalingProtocol protocol, - const buzz::XmlElement* action_elem, - const ContentParserMap& content_parsers, - const TransportParserMap& transport_parsers, - const CandidateTranslatorMap& translators, - SessionAccept* accept, - ParseError* error); -bool WriteSessionAccept(SignalingProtocol protocol, - const ContentInfos& contents, - const TransportInfos& tinfos, - const ContentParserMap& content_parsers, - const TransportParserMap& transport_parsers, - const CandidateTranslatorMap& translators, - const ContentGroups& groups, - XmlElements* elems, - WriteError* error); -bool ParseSessionTerminate(SignalingProtocol protocol, - const buzz::XmlElement* action_elem, - SessionTerminate* term, - ParseError* error); -void WriteSessionTerminate(SignalingProtocol protocol, - const SessionTerminate& term, - XmlElements* elems); -bool ParseDescriptionInfo(SignalingProtocol protocol, - const buzz::XmlElement* action_elem, - const ContentParserMap& content_parsers, - const TransportParserMap& transport_parsers, - const CandidateTranslatorMap& translators, - DescriptionInfo* description_info, - ParseError* error); -bool WriteDescriptionInfo(SignalingProtocol protocol, - const ContentInfos& contents, - const ContentParserMap& content_parsers, - XmlElements* elems, - WriteError* error); -// Since a TransportInfo is not a transport-info message, and a -// transport-info message is just a collection of TransportInfos, we -// say Parse/Write TransportInfos for transport-info messages. -bool ParseTransportInfos(SignalingProtocol protocol, - const buzz::XmlElement* action_elem, - const ContentInfos& contents, - const TransportParserMap& trans_parsers, - const CandidateTranslatorMap& translators, - TransportInfos* tinfos, - ParseError* error); -bool WriteTransportInfos(SignalingProtocol protocol, - const TransportInfos& tinfos, - const TransportParserMap& trans_parsers, - const CandidateTranslatorMap& translators, - XmlElements* elems, - WriteError* error); -// Handles both Gingle and Jingle syntax. -bool FindSessionRedirect(const buzz::XmlElement* stanza, - SessionRedirect* redirect); -} // namespace cricket - -#endif // WEBRTC_LIBJINGLE_SESSION_SESSIONMESSAGES_H_ diff --git a/webrtc/libjingle/session/sessionsendtask.h b/webrtc/libjingle/session/sessionsendtask.h deleted file mode 100644 index 195207c00..000000000 --- a/webrtc/libjingle/session/sessionsendtask.h +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright 2004 The WebRTC Project Authors. All rights reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#ifndef WEBRTC_LIBJINGLE_SESSION_SESSIONSENDTASK_H_ -#define WEBRTC_LIBJINGLE_SESSION_SESSIONSENDTASK_H_ - -#include "webrtc/libjingle/session/sessionmanager.h" -#include "webrtc/libjingle/xmpp/constants.h" -#include "webrtc/libjingle/xmpp/xmppclient.h" -#include "webrtc/libjingle/xmpp/xmppengine.h" -#include "webrtc/libjingle/xmpp/xmpptask.h" -#include "webrtc/base/common.h" - -namespace cricket { - -// The job of this task is to send an IQ stanza out (after stamping it with -// an ID attribute) and then wait for a response. If not response happens -// within 5 seconds, it will signal failure on a SessionManager. If an error -// happens it will also signal failure. If, however, the send succeeds this -// task will quietly go away. - -class SessionSendTask : public buzz::XmppTask { - public: - SessionSendTask(buzz::XmppTaskParentInterface* parent, - SessionManager* session_manager) - : buzz::XmppTask(parent, buzz::XmppEngine::HL_SINGLE), - session_manager_(session_manager) { - set_timeout_seconds(15); - session_manager_->SignalDestroyed.connect( - this, &SessionSendTask::OnSessionManagerDestroyed); - } - - virtual ~SessionSendTask() { - SignalDone(this); - } - - void Send(const buzz::XmlElement* stanza) { - ASSERT(stanza_.get() == NULL); - - // This should be an IQ of type set, result, or error. In the first case, - // we supply an ID. In the others, it should be present. - ASSERT(stanza->Name() == buzz::QN_IQ); - ASSERT(stanza->HasAttr(buzz::QN_TYPE)); - if (stanza->Attr(buzz::QN_TYPE) == "set") { - ASSERT(!stanza->HasAttr(buzz::QN_ID)); - } else { - ASSERT((stanza->Attr(buzz::QN_TYPE) == "result") || - (stanza->Attr(buzz::QN_TYPE) == "error")); - ASSERT(stanza->HasAttr(buzz::QN_ID)); - } - - stanza_.reset(new buzz::XmlElement(*stanza)); - if (stanza_->HasAttr(buzz::QN_ID)) { - set_task_id(stanza_->Attr(buzz::QN_ID)); - } else { - stanza_->SetAttr(buzz::QN_ID, task_id()); - } - } - - void OnSessionManagerDestroyed() { - // If the session manager doesn't exist anymore, we should still try to - // send the message, but avoid calling back into the SessionManager. - session_manager_ = NULL; - } - - sigslot::signal1 SignalDone; - - protected: - virtual int OnTimeout() { - if (session_manager_ != NULL) { - session_manager_->OnFailedSend(stanza_.get(), NULL); - } - - return XmppTask::OnTimeout(); - } - - virtual int ProcessStart() { - SendStanza(stanza_.get()); - if (stanza_->Attr(buzz::QN_TYPE) == buzz::STR_SET) { - return STATE_RESPONSE; - } else { - return STATE_DONE; - } - } - - virtual int ProcessResponse() { - const buzz::XmlElement* next = NextStanza(); - if (next == NULL) - return STATE_BLOCKED; - - if (session_manager_ != NULL) { - if (next->Attr(buzz::QN_TYPE) == buzz::STR_RESULT) { - session_manager_->OnIncomingResponse(stanza_.get(), next); - } else { - session_manager_->OnFailedSend(stanza_.get(), next); - } - } - - return STATE_DONE; - } - - virtual bool HandleStanza(const buzz::XmlElement *stanza) { - if (!MatchResponseIq(stanza, - buzz::Jid(stanza_->Attr(buzz::QN_TO)), task_id())) - return false; - if (stanza->Attr(buzz::QN_TYPE) == buzz::STR_RESULT || - stanza->Attr(buzz::QN_TYPE) == buzz::STR_ERROR) { - QueueStanza(stanza); - return true; - } - return false; - } - - private: - SessionManager *session_manager_; - rtc::scoped_ptr stanza_; -}; - -} - -#endif // WEBRTC_P2P_CLIENT_SESSIONSENDTASK_H_ diff --git a/webrtc/libjingle/session/transportparser.cc b/webrtc/libjingle/session/transportparser.cc deleted file mode 100644 index d438f8e6e..000000000 --- a/webrtc/libjingle/session/transportparser.cc +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2004 The WebRTC Project Authors. All rights reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#include "webrtc/libjingle/session/transportparser.h" - -#include "webrtc/libjingle/session/parsing.h" -#include "webrtc/libjingle/xmllite/xmlelement.h" -#include "webrtc/libjingle/xmpp/constants.h" - -namespace cricket { - -bool TransportParser::ParseAddress(const buzz::XmlElement* elem, - const buzz::QName& address_name, - const buzz::QName& port_name, - rtc::SocketAddress* address, - ParseError* error) { - if (!elem->HasAttr(address_name)) - return BadParse("address does not have " + address_name.LocalPart(), error); - if (!elem->HasAttr(port_name)) - return BadParse("address does not have " + port_name.LocalPart(), error); - - address->SetIP(elem->Attr(address_name)); - std::istringstream ist(elem->Attr(port_name)); - int port = 0; - ist >> port; - address->SetPort(port); - - return true; -} - -} // namespace cricket diff --git a/webrtc/libjingle/session/transportparser.h b/webrtc/libjingle/session/transportparser.h deleted file mode 100644 index 7512e7bc6..000000000 --- a/webrtc/libjingle/session/transportparser.h +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright 2004 The WebRTC Project Authors. All rights reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#ifndef WEBRTC_LIBJINGLE_SESSION_TRANSPORTPARSER_H_ -#define WEBRTC_LIBJINGLE_SESSION_TRANSPORTPARSER_H_ - -#include -#include - -#include "webrtc/p2p/base/transportinfo.h" - -namespace buzz { -class QName; -class XmlElement; -} - -namespace cricket { - -struct ParseError; -struct WriteError; -class CandidateTranslator; - -typedef std::vector XmlElements; - -class TransportParser { - public: - // The incoming Translator value may be null, in which case - // ParseCandidates should return false if there are candidates to - // parse (indicating a failure to parse). If the Translator is null - // and there are no candidates to parse, then return true, - // indicating a successful parse of 0 candidates. - - // Parse or write a transport description, including ICE credentials and - // any DTLS fingerprint. Since only Jingle has transport descriptions, these - // functions are only used when serializing to Jingle. - virtual bool ParseTransportDescription(const buzz::XmlElement* elem, - const CandidateTranslator* translator, - TransportDescription* tdesc, - ParseError* error) = 0; - virtual bool WriteTransportDescription(const TransportDescription& tdesc, - const CandidateTranslator* translator, - buzz::XmlElement** tdesc_elem, - WriteError* error) = 0; - - - // Parse a single candidate. This must be used when parsing Gingle - // candidates, since there is no enclosing transport description. - virtual bool ParseGingleCandidate(const buzz::XmlElement* elem, - const CandidateTranslator* translator, - Candidate* candidates, - ParseError* error) = 0; - virtual bool WriteGingleCandidate(const Candidate& candidate, - const CandidateTranslator* translator, - buzz::XmlElement** candidate_elem, - WriteError* error) = 0; - - // Helper function to parse an element describing an address. This - // retrieves the IP and port from the given element and verifies - // that they look like plausible values. - bool ParseAddress(const buzz::XmlElement* elem, - const buzz::QName& address_name, - const buzz::QName& port_name, - rtc::SocketAddress* address, - ParseError* error); - - virtual ~TransportParser() {} -}; - -} // namespace cricket - -#endif // WEBRTC_LIBJINGLE_SESSION_TRANSPORTPARSER_H_ diff --git a/webrtc/libjingle/session/transportparser_unittest.cc b/webrtc/libjingle/session/transportparser_unittest.cc deleted file mode 100644 index 1a61102cc..000000000 --- a/webrtc/libjingle/session/transportparser_unittest.cc +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright 2011 The WebRTC Project Authors. All rights reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. An additional intellectual property rights grant can be found - * in the file PATENTS. All contributing project authors may - * be found in the AUTHORS file in the root of the source tree. - */ - -#include "webrtc/base/gunit.h" -#include "webrtc/libjingle/session/p2ptransportparser.h" -#include "webrtc/libjingle/session/parsing.h" -#include "webrtc/libjingle/session/sessionmessages.h" -#include "webrtc/libjingle/xmllite/xmlelement.h" -#include "webrtc/libjingle/xmpp/constants.h" -#include "webrtc/p2p/base/constants.h" - -using cricket::Candidate; -using cricket::Candidates; -using cricket::ParseError; -using cricket::WriteError; - -class TransportParserTest : public testing::Test { -}; - -class FakeCandidateTranslator : public cricket::CandidateTranslator { - public: - void AddMapping(int component, const std::string& channel_name) { - name_to_component[channel_name] = component; - component_to_name[component] = channel_name; - } - - bool GetChannelNameFromComponent( - int component, std::string* channel_name) const { - if (component_to_name.find(component) == component_to_name.end()) { - return false; - } - *channel_name = component_to_name.find(component)->second; - return true; - } - bool GetComponentFromChannelName( - const std::string& channel_name, int* component) const { - if (name_to_component.find(channel_name) == name_to_component.end()) { - return false; - } - *component = name_to_component.find(channel_name)->second; - return true; - } - - std::map name_to_component; - std::map component_to_name; -}; - -// Tests that we can properly serialize/deserialize candidates. -TEST_F(TransportParserTest, TestP2PTransportWriteAndParseCandidate) { - Candidate test_candidate( - "", 1, "udp", - rtc::SocketAddress("2001:db8:fefe::1", 9999), - 738197504, "abcdef", "ghijkl", "foo", 50, ""); - test_candidate.set_network_name("testnet"); - Candidate test_candidate2( - "", 2, "tcp", - rtc::SocketAddress("192.168.7.1", 9999), - 1107296256, "mnopqr", "stuvwx", "bar", 100, ""); - test_candidate2.set_network_name("testnet2"); - rtc::SocketAddress host_address("www.google.com", 24601); - host_address.SetResolvedIP(rtc::IPAddress(0x0A000001)); - Candidate test_candidate3( - "", 3, "spdy", host_address, 1476395008, "yzabcd", - "efghij", "baz", 150, ""); - test_candidate3.set_network_name("testnet3"); - WriteError write_error; - ParseError parse_error; - rtc::scoped_ptr elem; - cricket::Candidate parsed_candidate; - cricket::P2PTransportParser parser; - - FakeCandidateTranslator translator; - translator.AddMapping(1, "test"); - translator.AddMapping(2, "test2"); - translator.AddMapping(3, "test3"); - - EXPECT_TRUE(parser.WriteGingleCandidate(test_candidate, &translator, - elem.accept(), &write_error)); - EXPECT_EQ("", write_error.text); - EXPECT_EQ("test", elem->Attr(buzz::QN_NAME)); - EXPECT_EQ("udp", elem->Attr(cricket::QN_PROTOCOL)); - EXPECT_EQ("2001:db8:fefe::1", elem->Attr(cricket::QN_ADDRESS)); - EXPECT_EQ("9999", elem->Attr(cricket::QN_PORT)); - EXPECT_EQ("0.34", elem->Attr(cricket::QN_PREFERENCE)); - EXPECT_EQ("abcdef", elem->Attr(cricket::QN_USERNAME)); - EXPECT_EQ("ghijkl", elem->Attr(cricket::QN_PASSWORD)); - EXPECT_EQ("foo", elem->Attr(cricket::QN_TYPE)); - EXPECT_EQ("testnet", elem->Attr(cricket::QN_NETWORK)); - EXPECT_EQ("50", elem->Attr(cricket::QN_GENERATION)); - - EXPECT_TRUE(parser.ParseGingleCandidate(elem.get(), &translator, - &parsed_candidate, &parse_error)); - EXPECT_TRUE(test_candidate.IsEquivalent(parsed_candidate)); - - EXPECT_TRUE(parser.WriteGingleCandidate(test_candidate2, &translator, - elem.accept(), &write_error)); - EXPECT_EQ("test2", elem->Attr(buzz::QN_NAME)); - EXPECT_EQ("tcp", elem->Attr(cricket::QN_PROTOCOL)); - EXPECT_EQ("192.168.7.1", elem->Attr(cricket::QN_ADDRESS)); - EXPECT_EQ("9999", elem->Attr(cricket::QN_PORT)); - EXPECT_EQ("0.51", elem->Attr(cricket::QN_PREFERENCE)); - EXPECT_EQ("mnopqr", elem->Attr(cricket::QN_USERNAME)); - EXPECT_EQ("stuvwx", elem->Attr(cricket::QN_PASSWORD)); - EXPECT_EQ("bar", elem->Attr(cricket::QN_TYPE)); - EXPECT_EQ("testnet2", elem->Attr(cricket::QN_NETWORK)); - EXPECT_EQ("100", elem->Attr(cricket::QN_GENERATION)); - - EXPECT_TRUE(parser.ParseGingleCandidate(elem.get(), &translator, - &parsed_candidate, &parse_error)); - EXPECT_TRUE(test_candidate2.IsEquivalent(parsed_candidate)); - - // Check that an ip is preferred over hostname. - EXPECT_TRUE(parser.WriteGingleCandidate(test_candidate3, &translator, - elem.accept(), &write_error)); - EXPECT_EQ("test3", elem->Attr(cricket::QN_NAME)); - EXPECT_EQ("spdy", elem->Attr(cricket::QN_PROTOCOL)); - EXPECT_EQ("10.0.0.1", elem->Attr(cricket::QN_ADDRESS)); - EXPECT_EQ("24601", elem->Attr(cricket::QN_PORT)); - EXPECT_EQ("0.69", elem->Attr(cricket::QN_PREFERENCE)); - EXPECT_EQ("yzabcd", elem->Attr(cricket::QN_USERNAME)); - EXPECT_EQ("efghij", elem->Attr(cricket::QN_PASSWORD)); - EXPECT_EQ("baz", elem->Attr(cricket::QN_TYPE)); - EXPECT_EQ("testnet3", elem->Attr(cricket::QN_NETWORK)); - EXPECT_EQ("150", elem->Attr(cricket::QN_GENERATION)); - - EXPECT_TRUE(parser.ParseGingleCandidate(elem.get(), &translator, - &parsed_candidate, &parse_error)); - EXPECT_TRUE(test_candidate3.IsEquivalent(parsed_candidate)); -} diff --git a/webrtc/libjingle/session/tunnel/pseudotcpchannel.cc b/webrtc/libjingle/session/tunnel/pseudotcpchannel.cc deleted file mode 100644 index c5b944325..000000000 --- a/webrtc/libjingle/session/tunnel/pseudotcpchannel.cc +++ /dev/null @@ -1,605 +0,0 @@ -/* - * libjingle - * Copyright 2004--2006, 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 -#include - -#include "pseudotcpchannel.h" -#include "webrtc/p2p/base/candidate.h" -#include "webrtc/p2p/base/transportchannel.h" -#include "webrtc/base/basictypes.h" -#include "webrtc/base/common.h" -#include "webrtc/base/logging.h" -#include "webrtc/base/scoped_ptr.h" -#include "webrtc/base/stringutils.h" - -using namespace rtc; - -namespace cricket { - -extern const rtc::ConstantLabel SESSION_STATES[]; - -// MSG_WK_* - worker thread messages -// MSG_ST_* - stream thread messages -// MSG_SI_* - signal thread messages - -enum { - MSG_WK_CLOCK = 1, - MSG_WK_PURGE, - MSG_ST_EVENT, - MSG_SI_DESTROYCHANNEL, - MSG_SI_DESTROY, -}; - -struct EventData : public MessageData { - int event, error; - EventData(int ev, int err = 0) : event(ev), error(err) { } -}; - -/////////////////////////////////////////////////////////////////////////////// -// PseudoTcpChannel::InternalStream -/////////////////////////////////////////////////////////////////////////////// - -class PseudoTcpChannel::InternalStream : public StreamInterface { -public: - InternalStream(PseudoTcpChannel* parent); - virtual ~InternalStream(); - - virtual StreamState GetState() const; - virtual StreamResult Read(void* buffer, size_t buffer_len, - size_t* read, int* error); - virtual StreamResult Write(const void* data, size_t data_len, - size_t* written, int* error); - virtual void Close(); - -private: - // parent_ is accessed and modified exclusively on the event thread, to - // avoid thread contention. This means that the PseudoTcpChannel cannot go - // away until after it receives a Close() from TunnelStream. - PseudoTcpChannel* parent_; -}; - -/////////////////////////////////////////////////////////////////////////////// -// PseudoTcpChannel -// Member object lifetime summaries: -// session_ - passed in constructor, cleared when channel_ goes away. -// channel_ - created in Connect, destroyed when session_ or tcp_ goes away. -// tcp_ - created in Connect, destroyed when channel_ goes away, or connection -// closes. -// worker_thread_ - created when channel_ is created, purged when channel_ is -// destroyed. -// stream_ - created in GetStream, destroyed by owner at arbitrary time. -// this - created in constructor, destroyed when worker_thread_ and stream_ -// are both gone. -/////////////////////////////////////////////////////////////////////////////// - -// -// Signal thread methods -// - -PseudoTcpChannel::PseudoTcpChannel(Thread* stream_thread, Session* session) - : signal_thread_(session->session_manager()->signaling_thread()), - worker_thread_(NULL), - stream_thread_(stream_thread), - session_(session), channel_(NULL), tcp_(NULL), stream_(NULL), - stream_readable_(false), pending_read_event_(false), - ready_to_connect_(false) { - ASSERT(signal_thread_->IsCurrent()); - ASSERT(NULL != session_); -} - -PseudoTcpChannel::~PseudoTcpChannel() { - ASSERT(signal_thread_->IsCurrent()); - ASSERT(worker_thread_ == NULL); - ASSERT(session_ == NULL); - ASSERT(channel_ == NULL); - ASSERT(stream_ == NULL); - ASSERT(tcp_ == NULL); -} - -bool PseudoTcpChannel::Connect(const std::string& content_name, - const std::string& channel_name, - int component) { - ASSERT(signal_thread_->IsCurrent()); - CritScope lock(&cs_); - - if (channel_) - return false; - - ASSERT(session_ != NULL); - worker_thread_ = session_->session_manager()->worker_thread(); - content_name_ = content_name; - channel_ = session_->CreateChannel( - content_name, channel_name, component); - channel_name_ = channel_name; - channel_->SetOption(Socket::OPT_DONTFRAGMENT, 1); - - channel_->SignalDestroyed.connect(this, - &PseudoTcpChannel::OnChannelDestroyed); - channel_->SignalWritableState.connect(this, - &PseudoTcpChannel::OnChannelWritableState); - channel_->SignalReadPacket.connect(this, - &PseudoTcpChannel::OnChannelRead); - channel_->SignalRouteChange.connect(this, - &PseudoTcpChannel::OnChannelConnectionChanged); - - ASSERT(tcp_ == NULL); - tcp_ = new PseudoTcp(this, 0); - if (session_->initiator()) { - // Since we may try several protocols and network adapters that won't work, - // waiting until we get our first writable notification before initiating - // TCP negotiation. - ready_to_connect_ = true; - } - - return true; -} - -StreamInterface* PseudoTcpChannel::GetStream() { - ASSERT(signal_thread_->IsCurrent()); - CritScope lock(&cs_); - ASSERT(NULL != session_); - if (!stream_) - stream_ = new PseudoTcpChannel::InternalStream(this); - //TODO("should we disallow creation of new stream at some point?"); - return stream_; -} - -void PseudoTcpChannel::OnChannelDestroyed(TransportChannel* channel) { - LOG_F(LS_INFO) << "(" << channel->component() << ")"; - ASSERT(signal_thread_->IsCurrent()); - CritScope lock(&cs_); - ASSERT(channel == channel_); - signal_thread_->Clear(this, MSG_SI_DESTROYCHANNEL); - // When MSG_WK_PURGE is received, we know there will be no more messages from - // the worker thread. - worker_thread_->Clear(this, MSG_WK_CLOCK); - worker_thread_->Post(this, MSG_WK_PURGE); - session_ = NULL; - channel_ = NULL; - if ((stream_ != NULL) - && ((tcp_ == NULL) || (tcp_->State() != PseudoTcp::TCP_CLOSED))) - stream_thread_->Post(this, MSG_ST_EVENT, new EventData(SE_CLOSE, 0)); - if (tcp_) { - tcp_->Close(true); - AdjustClock(); - } - SignalChannelClosed(this); -} - -void PseudoTcpChannel::OnSessionTerminate(Session* session) { - // When the session terminates before we even connected - CritScope lock(&cs_); - if (session_ != NULL && channel_ == NULL) { - ASSERT(session == session_); - ASSERT(worker_thread_ == NULL); - ASSERT(tcp_ == NULL); - LOG(LS_INFO) << "Destroying unconnected PseudoTcpChannel"; - session_ = NULL; - if (stream_ != NULL) - stream_thread_->Post(this, MSG_ST_EVENT, new EventData(SE_CLOSE, -1)); - } - - // Even though session_ is being destroyed, we mustn't clear the pointer, - // since we'll need it to tear down channel_. - // - // TODO: Is it always the case that if channel_ != NULL then we'll get - // a channel-destroyed notification? -} - -void PseudoTcpChannel::GetOption(PseudoTcp::Option opt, int* value) { - ASSERT(signal_thread_->IsCurrent()); - CritScope lock(&cs_); - ASSERT(tcp_ != NULL); - tcp_->GetOption(opt, value); -} - -void PseudoTcpChannel::SetOption(PseudoTcp::Option opt, int value) { - ASSERT(signal_thread_->IsCurrent()); - CritScope lock(&cs_); - ASSERT(tcp_ != NULL); - tcp_->SetOption(opt, value); -} - -// -// Stream thread methods -// - -StreamState PseudoTcpChannel::GetState() const { - ASSERT(stream_ != NULL && stream_thread_->IsCurrent()); - CritScope lock(&cs_); - if (!session_) - return SS_CLOSED; - if (!tcp_) - return SS_OPENING; - switch (tcp_->State()) { - case PseudoTcp::TCP_LISTEN: - case PseudoTcp::TCP_SYN_SENT: - case PseudoTcp::TCP_SYN_RECEIVED: - return SS_OPENING; - case PseudoTcp::TCP_ESTABLISHED: - return SS_OPEN; - case PseudoTcp::TCP_CLOSED: - default: - return SS_CLOSED; - } -} - -StreamResult PseudoTcpChannel::Read(void* buffer, size_t buffer_len, - size_t* read, int* error) { - ASSERT(stream_ != NULL && stream_thread_->IsCurrent()); - CritScope lock(&cs_); - if (!tcp_) - return SR_BLOCK; - - stream_readable_ = false; - int result = tcp_->Recv(static_cast(buffer), buffer_len); - //LOG_F(LS_VERBOSE) << "Recv returned: " << result; - if (result > 0) { - if (read) - *read = result; - // PseudoTcp doesn't currently support repeated Readable signals. Simulate - // them here. - stream_readable_ = true; - if (!pending_read_event_) { - pending_read_event_ = true; - stream_thread_->Post(this, MSG_ST_EVENT, new EventData(SE_READ), true); - } - return SR_SUCCESS; - } else if (IsBlockingError(tcp_->GetError())) { - return SR_BLOCK; - } else { - if (error) - *error = tcp_->GetError(); - return SR_ERROR; - } - // This spot is never reached. -} - -StreamResult PseudoTcpChannel::Write(const void* data, size_t data_len, - size_t* written, int* error) { - ASSERT(stream_ != NULL && stream_thread_->IsCurrent()); - CritScope lock(&cs_); - if (!tcp_) - return SR_BLOCK; - int result = tcp_->Send(static_cast(data), data_len); - //LOG_F(LS_VERBOSE) << "Send returned: " << result; - if (result > 0) { - if (written) - *written = result; - return SR_SUCCESS; - } else if (IsBlockingError(tcp_->GetError())) { - return SR_BLOCK; - } else { - if (error) - *error = tcp_->GetError(); - return SR_ERROR; - } - // This spot is never reached. -} - -void PseudoTcpChannel::Close() { - ASSERT(stream_ != NULL && stream_thread_->IsCurrent()); - CritScope lock(&cs_); - stream_ = NULL; - // Clear out any pending event notifications - stream_thread_->Clear(this, MSG_ST_EVENT); - if (tcp_) { - tcp_->Close(false); - AdjustClock(); - } else { - CheckDestroy(); - } -} - -// -// Worker thread methods -// - -void PseudoTcpChannel::OnChannelWritableState(TransportChannel* channel) { - LOG_F(LS_VERBOSE) << "[" << channel_name_ << "]"; - ASSERT(worker_thread_->IsCurrent()); - CritScope lock(&cs_); - if (!channel_) { - LOG_F(LS_WARNING) << "NULL channel"; - return; - } - ASSERT(channel == channel_); - if (!tcp_) { - LOG_F(LS_WARNING) << "NULL tcp"; - return; - } - if (!ready_to_connect_ || !channel->writable()) - return; - - ready_to_connect_ = false; - tcp_->Connect(); - AdjustClock(); -} - -void PseudoTcpChannel::OnChannelRead(TransportChannel* channel, - const char* data, size_t size, - const rtc::PacketTime& packet_time, - int flags) { - //LOG_F(LS_VERBOSE) << "(" << size << ")"; - ASSERT(worker_thread_->IsCurrent()); - CritScope lock(&cs_); - if (!channel_) { - LOG_F(LS_WARNING) << "NULL channel"; - return; - } - ASSERT(channel == channel_); - if (!tcp_) { - LOG_F(LS_WARNING) << "NULL tcp"; - return; - } - tcp_->NotifyPacket(data, size); - AdjustClock(); -} - -void PseudoTcpChannel::OnChannelConnectionChanged(TransportChannel* channel, - const Candidate& candidate) { - LOG_F(LS_VERBOSE) << "[" << channel_name_ << "]"; - ASSERT(worker_thread_->IsCurrent()); - CritScope lock(&cs_); - if (!channel_) { - LOG_F(LS_WARNING) << "NULL channel"; - return; - } - ASSERT(channel == channel_); - if (!tcp_) { - LOG_F(LS_WARNING) << "NULL tcp"; - return; - } - - uint16 mtu = 1280; // safe default - int family = candidate.address().family(); - Socket* socket = - worker_thread_->socketserver()->CreateAsyncSocket(family, SOCK_DGRAM); - rtc::scoped_ptr mtu_socket(socket); - if (socket == NULL) { - LOG_F(LS_WARNING) << "Couldn't create socket while estimating MTU."; - } else { - if (mtu_socket->Connect(candidate.address()) < 0 || - mtu_socket->EstimateMTU(&mtu) < 0) { - LOG_F(LS_WARNING) << "Failed to estimate MTU, error=" - << mtu_socket->GetError(); - } - } - - LOG_F(LS_VERBOSE) << "Using MTU of " << mtu << " bytes"; - tcp_->NotifyMTU(mtu); - AdjustClock(); -} - -void PseudoTcpChannel::OnTcpOpen(PseudoTcp* tcp) { - LOG_F(LS_VERBOSE) << "[" << channel_name_ << "]"; - ASSERT(cs_.CurrentThreadIsOwner()); - ASSERT(worker_thread_->IsCurrent()); - ASSERT(tcp == tcp_); - if (stream_) { - stream_readable_ = true; - pending_read_event_ = true; - stream_thread_->Post(this, MSG_ST_EVENT, - new EventData(SE_OPEN | SE_READ | SE_WRITE)); - } -} - -void PseudoTcpChannel::OnTcpReadable(PseudoTcp* tcp) { - //LOG_F(LS_VERBOSE); - ASSERT(cs_.CurrentThreadIsOwner()); - ASSERT(worker_thread_->IsCurrent()); - ASSERT(tcp == tcp_); - if (stream_) { - stream_readable_ = true; - if (!pending_read_event_) { - pending_read_event_ = true; - stream_thread_->Post(this, MSG_ST_EVENT, new EventData(SE_READ)); - } - } -} - -void PseudoTcpChannel::OnTcpWriteable(PseudoTcp* tcp) { - //LOG_F(LS_VERBOSE); - ASSERT(cs_.CurrentThreadIsOwner()); - ASSERT(worker_thread_->IsCurrent()); - ASSERT(tcp == tcp_); - if (stream_) - stream_thread_->Post(this, MSG_ST_EVENT, new EventData(SE_WRITE)); -} - -void PseudoTcpChannel::OnTcpClosed(PseudoTcp* tcp, uint32 nError) { - LOG_F(LS_VERBOSE) << "[" << channel_name_ << "]"; - ASSERT(cs_.CurrentThreadIsOwner()); - ASSERT(worker_thread_->IsCurrent()); - ASSERT(tcp == tcp_); - if (stream_) - stream_thread_->Post(this, MSG_ST_EVENT, new EventData(SE_CLOSE, nError)); -} - -// -// Multi-thread methods -// - -void PseudoTcpChannel::OnMessage(Message* pmsg) { - if (pmsg->message_id == MSG_WK_CLOCK) { - - ASSERT(worker_thread_->IsCurrent()); - //LOG(LS_INFO) << "PseudoTcpChannel::OnMessage(MSG_WK_CLOCK)"; - CritScope lock(&cs_); - if (tcp_) { - tcp_->NotifyClock(PseudoTcp::Now()); - AdjustClock(false); - } - - } else if (pmsg->message_id == MSG_WK_PURGE) { - - ASSERT(worker_thread_->IsCurrent()); - LOG_F(LS_INFO) << "(MSG_WK_PURGE)"; - // At this point, we know there are no additional worker thread messages. - CritScope lock(&cs_); - ASSERT(NULL == session_); - ASSERT(NULL == channel_); - worker_thread_ = NULL; - CheckDestroy(); - - } else if (pmsg->message_id == MSG_ST_EVENT) { - - ASSERT(stream_thread_->IsCurrent()); - //LOG(LS_INFO) << "PseudoTcpChannel::OnMessage(MSG_ST_EVENT, " - // << data->event << ", " << data->error << ")"; - ASSERT(stream_ != NULL); - EventData* data = static_cast(pmsg->pdata); - if (data->event & SE_READ) { - CritScope lock(&cs_); - pending_read_event_ = false; - } - stream_->SignalEvent(stream_, data->event, data->error); - delete data; - - } else if (pmsg->message_id == MSG_SI_DESTROYCHANNEL) { - - ASSERT(signal_thread_->IsCurrent()); - LOG_F(LS_INFO) << "(MSG_SI_DESTROYCHANNEL)"; - ASSERT(session_ != NULL); - ASSERT(channel_ != NULL); - session_->DestroyChannel(content_name_, channel_->component()); - - } else if (pmsg->message_id == MSG_SI_DESTROY) { - - ASSERT(signal_thread_->IsCurrent()); - LOG_F(LS_INFO) << "(MSG_SI_DESTROY)"; - // The message queue is empty, so it is safe to destroy ourselves. - delete this; - - } else { - ASSERT(false); - } -} - -IPseudoTcpNotify::WriteResult PseudoTcpChannel::TcpWritePacket( - PseudoTcp* tcp, const char* buffer, size_t len) { - ASSERT(cs_.CurrentThreadIsOwner()); - ASSERT(tcp == tcp_); - ASSERT(NULL != channel_); - rtc::PacketOptions packet_options; - int sent = channel_->SendPacket(buffer, len, packet_options); - if (sent > 0) { - //LOG_F(LS_VERBOSE) << "(" << sent << ") Sent"; - return IPseudoTcpNotify::WR_SUCCESS; - } else if (IsBlockingError(channel_->GetError())) { - LOG_F(LS_VERBOSE) << "Blocking"; - return IPseudoTcpNotify::WR_SUCCESS; - } else if (channel_->GetError() == EMSGSIZE) { - LOG_F(LS_ERROR) << "EMSGSIZE"; - return IPseudoTcpNotify::WR_TOO_LARGE; - } else { - PLOG(LS_ERROR, channel_->GetError()) << "PseudoTcpChannel::TcpWritePacket"; - ASSERT(false); - return IPseudoTcpNotify::WR_FAIL; - } -} - -void PseudoTcpChannel::AdjustClock(bool clear) { - ASSERT(cs_.CurrentThreadIsOwner()); - ASSERT(NULL != tcp_); - - long timeout = 0; - if (tcp_->GetNextClock(PseudoTcp::Now(), timeout)) { - ASSERT(NULL != channel_); - // Reset the next clock, by clearing the old and setting a new one. - if (clear) - worker_thread_->Clear(this, MSG_WK_CLOCK); - worker_thread_->PostDelayed(std::max(timeout, 0L), this, MSG_WK_CLOCK); - return; - } - - delete tcp_; - tcp_ = NULL; - ready_to_connect_ = false; - - if (channel_) { - // If TCP has failed, no need for channel_ anymore - signal_thread_->Post(this, MSG_SI_DESTROYCHANNEL); - } -} - -void PseudoTcpChannel::CheckDestroy() { - ASSERT(cs_.CurrentThreadIsOwner()); - if ((worker_thread_ != NULL) || (stream_ != NULL)) - return; - signal_thread_->Post(this, MSG_SI_DESTROY); -} - -/////////////////////////////////////////////////////////////////////////////// -// PseudoTcpChannel::InternalStream -/////////////////////////////////////////////////////////////////////////////// - -PseudoTcpChannel::InternalStream::InternalStream(PseudoTcpChannel* parent) - : parent_(parent) { -} - -PseudoTcpChannel::InternalStream::~InternalStream() { - Close(); -} - -StreamState PseudoTcpChannel::InternalStream::GetState() const { - if (!parent_) - return SS_CLOSED; - return parent_->GetState(); -} - -StreamResult PseudoTcpChannel::InternalStream::Read( - void* buffer, size_t buffer_len, size_t* read, int* error) { - if (!parent_) { - if (error) - *error = ENOTCONN; - return SR_ERROR; - } - return parent_->Read(buffer, buffer_len, read, error); -} - -StreamResult PseudoTcpChannel::InternalStream::Write( - const void* data, size_t data_len, size_t* written, int* error) { - if (!parent_) { - if (error) - *error = ENOTCONN; - return SR_ERROR; - } - return parent_->Write(data, data_len, written, error); -} - -void PseudoTcpChannel::InternalStream::Close() { - if (!parent_) - return; - parent_->Close(); - parent_ = NULL; -} - -/////////////////////////////////////////////////////////////////////////////// - -} // namespace cricket diff --git a/webrtc/libjingle/session/tunnel/pseudotcpchannel.h b/webrtc/libjingle/session/tunnel/pseudotcpchannel.h deleted file mode 100644 index 7397a0682..000000000 --- a/webrtc/libjingle/session/tunnel/pseudotcpchannel.h +++ /dev/null @@ -1,140 +0,0 @@ -/* - * libjingle - * Copyright 2004--2006, 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 WEBRTC_LIBJINGLE_SESSION_TUNNEL_PSEUDOTCPCHANNEL_H_ -#define WEBRTC_LIBJINGLE_SESSION_TUNNEL_PSEUDOTCPCHANNEL_H_ - -#include "webrtc/base/criticalsection.h" -#include "webrtc/base/messagequeue.h" -#include "webrtc/base/stream.h" -#include "webrtc/libjingle/session/sessionmanager.h" -#include "webrtc/p2p/base/pseudotcp.h" - -namespace rtc { -class Thread; -} - -namespace cricket { - -class Candidate; -class TransportChannel; - -/////////////////////////////////////////////////////////////////////////////// -// PseudoTcpChannel -// Note: The PseudoTcpChannel must persist until both of: -// 1) The StreamInterface provided via GetStream has been closed. -// This is tracked via non-null stream_. -// 2) The PseudoTcp session has completed. -// This is tracked via non-null worker_thread_. When PseudoTcp is done, -// the TransportChannel is signalled to tear-down. Once the channel is -// torn down, the worker thread is purged. -// These indicators are checked by CheckDestroy, invoked whenever one of them -// changes. -/////////////////////////////////////////////////////////////////////////////// -// PseudoTcpChannel::GetStream -// Note: The stream pointer returned by GetStream is owned by the caller. -// They can close & immediately delete the stream while PseudoTcpChannel still -// has cleanup work to do. They can also close the stream but not delete it -// until long after PseudoTcpChannel has finished. We must cope with both. -/////////////////////////////////////////////////////////////////////////////// - -class PseudoTcpChannel - : public IPseudoTcpNotify, - public rtc::MessageHandler, - public sigslot::has_slots<> { - public: - // Signal thread methods - PseudoTcpChannel(rtc::Thread* stream_thread, - Session* session); - - bool Connect(const std::string& content_name, - const std::string& channel_name, - int component); - rtc::StreamInterface* GetStream(); - - sigslot::signal1 SignalChannelClosed; - - // Call this when the Session used to create this channel is being torn - // down, to ensure that things get cleaned up properly. - void OnSessionTerminate(Session* session); - - // See the PseudoTcp class for available options. - void GetOption(PseudoTcp::Option opt, int* value); - void SetOption(PseudoTcp::Option opt, int value); - - private: - class InternalStream; - friend class InternalStream; - - virtual ~PseudoTcpChannel(); - - // Stream thread methods - rtc::StreamState GetState() const; - rtc::StreamResult Read(void* buffer, size_t buffer_len, - size_t* read, int* error); - rtc::StreamResult Write(const void* data, size_t data_len, - size_t* written, int* error); - void Close(); - - // Multi-thread methods - void OnMessage(rtc::Message* pmsg); - void AdjustClock(bool clear = true); - void CheckDestroy(); - - // Signal thread methods - void OnChannelDestroyed(TransportChannel* channel); - - // Worker thread methods - void OnChannelWritableState(TransportChannel* channel); - void OnChannelRead(TransportChannel* channel, const char* data, size_t size, - const rtc::PacketTime& packet_time, int flags); - void OnChannelConnectionChanged(TransportChannel* channel, - const Candidate& candidate); - - virtual void OnTcpOpen(PseudoTcp* ptcp); - virtual void OnTcpReadable(PseudoTcp* ptcp); - virtual void OnTcpWriteable(PseudoTcp* ptcp); - virtual void OnTcpClosed(PseudoTcp* ptcp, uint32 nError); - virtual IPseudoTcpNotify::WriteResult TcpWritePacket(PseudoTcp* tcp, - const char* buffer, - size_t len); - - rtc::Thread* signal_thread_, * worker_thread_, * stream_thread_; - Session* session_; - TransportChannel* channel_; - std::string content_name_; - std::string channel_name_; - PseudoTcp* tcp_; - InternalStream* stream_; - bool stream_readable_, pending_read_event_; - bool ready_to_connect_; - mutable rtc::CriticalSection cs_; -}; - -} // namespace cricket - -#endif // WEBRTC_LIBJINGLE_SESSION_TUNNEL_PSEUDOTCPCHANNEL_H_ diff --git a/webrtc/libjingle/session/tunnel/securetunnelsessionclient.cc b/webrtc/libjingle/session/tunnel/securetunnelsessionclient.cc deleted file mode 100644 index 5f6f9dfdf..000000000 --- a/webrtc/libjingle/session/tunnel/securetunnelsessionclient.cc +++ /dev/null @@ -1,397 +0,0 @@ -/* - * libjingle - * Copyright 2004--2008, 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. - */ - -// SecureTunnelSessionClient and SecureTunnelSession implementation. - -#include "webrtc/p2p/base/transportchannel.h" -#include "webrtc/libjingle/session/tunnel/pseudotcpchannel.h" -#include "webrtc/libjingle/session/tunnel/securetunnelsessionclient.h" -#include "webrtc/libjingle/xmllite/xmlelement.h" -#include "webrtc/base/basicdefs.h" -#include "webrtc/base/basictypes.h" -#include "webrtc/base/common.h" -#include "webrtc/base/helpers.h" -#include "webrtc/base/logging.h" -#include "webrtc/base/sslidentity.h" -#include "webrtc/base/sslstreamadapter.h" -#include "webrtc/base/stringutils.h" - -namespace cricket { - -// XML elements and namespaces for XMPP stanzas used in content exchanges. - -const char NS_SECURE_TUNNEL[] = "http://www.google.com/talk/securetunnel"; -const buzz::StaticQName QN_SECURE_TUNNEL_DESCRIPTION = - { NS_SECURE_TUNNEL, "description" }; -const buzz::StaticQName QN_SECURE_TUNNEL_TYPE = - { NS_SECURE_TUNNEL, "type" }; -const buzz::StaticQName QN_SECURE_TUNNEL_CLIENT_CERT = - { NS_SECURE_TUNNEL, "client-cert" }; -const buzz::StaticQName QN_SECURE_TUNNEL_SERVER_CERT = - { NS_SECURE_TUNNEL, "server-cert" }; -const char CN_SECURE_TUNNEL[] = "securetunnel"; - -// SecureTunnelContentDescription - -// TunnelContentDescription is extended to hold string forms of the -// client and server certificate, PEM encoded. - -struct SecureTunnelContentDescription : public ContentDescription { - std::string description; - std::string client_pem_certificate; - std::string server_pem_certificate; - - SecureTunnelContentDescription(const std::string& desc, - const std::string& client_pem_cert, - const std::string& server_pem_cert) - : description(desc), - client_pem_certificate(client_pem_cert), - server_pem_certificate(server_pem_cert) { - } - virtual ContentDescription* Copy() const { - return new SecureTunnelContentDescription(*this); - } -}; - -// SecureTunnelSessionClient - -SecureTunnelSessionClient::SecureTunnelSessionClient( - const buzz::Jid& jid, SessionManager* manager) - : TunnelSessionClient(jid, manager, NS_SECURE_TUNNEL) { -} - -void SecureTunnelSessionClient::SetIdentity(rtc::SSLIdentity* identity) { - ASSERT(identity_.get() == NULL); - identity_.reset(identity); -} - -bool SecureTunnelSessionClient::GenerateIdentity() { - ASSERT(identity_.get() == NULL); - identity_.reset(rtc::SSLIdentity::Generate( - // The name on the certificate does not matter: the peer will - // make sure the cert it gets during SSL negotiation matches the - // one it got from XMPP. It would be neat to put something - // recognizable in there such as the JID, except this will show - // in clear during the SSL negotiation and so it could be a - // privacy issue. Specifying an empty string here causes - // it to use a random string. -#ifdef _DEBUG - jid().Str() -#else - "" -#endif - )); - if (identity_.get() == NULL) { - LOG(LS_ERROR) << "Failed to generate SSL identity"; - return false; - } - return true; -} - -rtc::SSLIdentity& SecureTunnelSessionClient::GetIdentity() const { - ASSERT(identity_.get() != NULL); - return *identity_; -} - -// Parses a certificate from a PEM encoded string. -// Returns NULL on failure. -// The caller is responsible for freeing the returned object. -static rtc::SSLCertificate* ParseCertificate( - const std::string& pem_cert) { - if (pem_cert.empty()) - return NULL; - return rtc::SSLCertificate::FromPEMString(pem_cert); -} - -TunnelSession* SecureTunnelSessionClient::MakeTunnelSession( - Session* session, rtc::Thread* stream_thread, - TunnelSessionRole role) { - return new SecureTunnelSession(this, session, stream_thread, role); -} - -bool FindSecureTunnelContent(const cricket::SessionDescription* sdesc, - std::string* name, - const SecureTunnelContentDescription** content) { - const ContentInfo* cinfo = sdesc->FirstContentByType(NS_SECURE_TUNNEL); - if (cinfo == NULL) - return false; - - *name = cinfo->name; - *content = static_cast( - cinfo->description); - return true; -} - -void SecureTunnelSessionClient::OnIncomingTunnel(const buzz::Jid &jid, - Session *session) { - std::string content_name; - const SecureTunnelContentDescription* content = NULL; - if (!FindSecureTunnelContent(session->remote_description(), - &content_name, &content)) { - ASSERT(false); - } - - // Validate the certificate - rtc::scoped_ptr peer_cert( - ParseCertificate(content->client_pem_certificate)); - if (peer_cert.get() == NULL) { - LOG(LS_ERROR) - << "Rejecting incoming secure tunnel with invalid cetificate"; - DeclineTunnel(session); - return; - } - // If there were a convenient place we could have cached the - // peer_cert so as not to have to parse it a second time when - // configuring the tunnel. - SignalIncomingTunnel(this, jid, content->description, session); -} - -// The XML representation of a session initiation request (XMPP IQ), -// containing the initiator's SecureTunnelContentDescription, -// looks something like this: -// -// -// -// send:filename -// -// -----BEGIN CERTIFICATE----- -// INITIATOR'S CERTIFICATE IN PERM FORMAT (ASCII GIBBERISH) -// -----END CERTIFICATE----- -// -// -// -// -// - -// The session accept iq, containing the recipient's certificate and -// echoing the initiator's certificate, looks something like this: -// -// -// -// send:FILENAME -// -// -----BEGIN CERTIFICATE----- -// INITIATOR'S CERTIFICATE IN PERM FORMAT (ASCII GIBBERISH) -// -----END CERTIFICATE----- -// -// -// -----BEGIN CERTIFICATE----- -// RECIPIENT'S CERTIFICATE IN PERM FORMAT (ASCII GIBBERISH) -// -----END CERTIFICATE----- -// -// -// -// - - -bool SecureTunnelSessionClient::ParseContent(SignalingProtocol protocol, - const buzz::XmlElement* elem, - ContentDescription** content, - ParseError* error) { - const buzz::XmlElement* type_elem = elem->FirstNamed(QN_SECURE_TUNNEL_TYPE); - - if (type_elem == NULL) - // Missing mandatory XML element. - return false; - - // Here we consider the certificate components to be optional. In - // practice the client certificate is always present, and the server - // certificate is initially missing from the session description - // sent during session initiation. OnAccept() will enforce that we - // have a certificate for our peer. - const buzz::XmlElement* client_cert_elem = - elem->FirstNamed(QN_SECURE_TUNNEL_CLIENT_CERT); - const buzz::XmlElement* server_cert_elem = - elem->FirstNamed(QN_SECURE_TUNNEL_SERVER_CERT); - *content = new SecureTunnelContentDescription( - type_elem->BodyText(), - client_cert_elem ? client_cert_elem->BodyText() : "", - server_cert_elem ? server_cert_elem->BodyText() : ""); - return true; -} - -bool SecureTunnelSessionClient::WriteContent( - SignalingProtocol protocol, const ContentDescription* untyped_content, - buzz::XmlElement** elem, WriteError* error) { - const SecureTunnelContentDescription* content = - static_cast(untyped_content); - - buzz::XmlElement* root = - new buzz::XmlElement(QN_SECURE_TUNNEL_DESCRIPTION, true); - buzz::XmlElement* type_elem = new buzz::XmlElement(QN_SECURE_TUNNEL_TYPE); - type_elem->SetBodyText(content->description); - root->AddElement(type_elem); - if (!content->client_pem_certificate.empty()) { - buzz::XmlElement* client_cert_elem = - new buzz::XmlElement(QN_SECURE_TUNNEL_CLIENT_CERT); - client_cert_elem->SetBodyText(content->client_pem_certificate); - root->AddElement(client_cert_elem); - } - if (!content->server_pem_certificate.empty()) { - buzz::XmlElement* server_cert_elem = - new buzz::XmlElement(QN_SECURE_TUNNEL_SERVER_CERT); - server_cert_elem->SetBodyText(content->server_pem_certificate); - root->AddElement(server_cert_elem); - } - *elem = root; - return true; -} - -SessionDescription* NewSecureTunnelSessionDescription( - const std::string& content_name, ContentDescription* content) { - SessionDescription* sdesc = new SessionDescription(); - sdesc->AddContent(content_name, NS_SECURE_TUNNEL, content); - return sdesc; -} - -SessionDescription* SecureTunnelSessionClient::CreateOffer( - const buzz::Jid &jid, const std::string &description) { - // We are the initiator so we are the client. Put our cert into the - // description. - std::string pem_cert = GetIdentity().certificate().ToPEMString(); - return NewSecureTunnelSessionDescription( - CN_SECURE_TUNNEL, - new SecureTunnelContentDescription(description, pem_cert, "")); -} - -SessionDescription* SecureTunnelSessionClient::CreateAnswer( - const SessionDescription* offer) { - std::string content_name; - const SecureTunnelContentDescription* offer_tunnel = NULL; - if (!FindSecureTunnelContent(offer, &content_name, &offer_tunnel)) - return NULL; - - // We are accepting a session request. We need to add our cert, the - // server cert, into the description. The client cert was validated - // in OnIncomingTunnel(). - ASSERT(!offer_tunnel->client_pem_certificate.empty()); - return NewSecureTunnelSessionDescription( - content_name, - new SecureTunnelContentDescription( - offer_tunnel->description, - offer_tunnel->client_pem_certificate, - GetIdentity().certificate().ToPEMString())); -} - -// SecureTunnelSession - -SecureTunnelSession::SecureTunnelSession( - SecureTunnelSessionClient* client, Session* session, - rtc::Thread* stream_thread, TunnelSessionRole role) - : TunnelSession(client, session, stream_thread), - role_(role) { -} - -rtc::StreamInterface* SecureTunnelSession::MakeSecureStream( - rtc::StreamInterface* stream) { - rtc::SSLStreamAdapter* ssl_stream = - rtc::SSLStreamAdapter::Create(stream); - rtc::SSLIdentity* identity = - static_cast(client_)-> - GetIdentity().GetReference(); - ssl_stream->SetIdentity(identity); - if (role_ == RESPONDER) - ssl_stream->SetServerRole(); - ssl_stream->StartSSLWithPeer(); - - // SSL negotiation will start on the stream as soon as it - // opens. However our SSLStreamAdapter still hasn't been told what - // certificate to allow for our peer. If we are the initiator, we do - // not have the peer's certificate yet: we will obtain it from the - // session accept message which we will receive later (see - // OnAccept()). We won't Connect() the PseudoTcpChannel until we get - // that, so the stream will stay closed until then. Keep a handle - // on the streem so we can configure the peer certificate later. - ssl_stream_reference_.reset(new rtc::StreamReference(ssl_stream)); - return ssl_stream_reference_->NewReference(); -} - -rtc::StreamInterface* SecureTunnelSession::GetStream() { - ASSERT(channel_ != NULL); - ASSERT(ssl_stream_reference_.get() == NULL); - return MakeSecureStream(channel_->GetStream()); -} - -void SecureTunnelSession::OnAccept() { - // We have either sent or received a session accept: it's time to - // connect the tunnel. First we must set the peer certificate. - ASSERT(channel_ != NULL); - ASSERT(session_ != NULL); - std::string content_name; - const SecureTunnelContentDescription* remote_tunnel = NULL; - if (!FindSecureTunnelContent(session_->remote_description(), - &content_name, &remote_tunnel)) { - session_->Reject(STR_TERMINATE_INCOMPATIBLE_PARAMETERS); - return; - } - - const std::string& cert_pem = - role_ == INITIATOR ? remote_tunnel->server_pem_certificate : - remote_tunnel->client_pem_certificate; - rtc::scoped_ptr peer_cert( - ParseCertificate(cert_pem)); - if (peer_cert == NULL) { - ASSERT(role_ == INITIATOR); // when RESPONDER we validated it earlier - LOG(LS_ERROR) - << "Rejecting secure tunnel accept with invalid cetificate"; - session_->Reject(STR_TERMINATE_INCOMPATIBLE_PARAMETERS); - return; - } - ASSERT(ssl_stream_reference_.get() != NULL); - rtc::SSLStreamAdapter* ssl_stream = - static_cast( - ssl_stream_reference_->GetStream()); - - std::string algorithm; - if (!peer_cert->GetSignatureDigestAlgorithm(&algorithm)) { - LOG(LS_ERROR) << "Failed to get the algorithm for the peer cert signature"; - return; - } - unsigned char digest[rtc::MessageDigest::kMaxSize]; - size_t digest_len; - peer_cert->ComputeDigest(algorithm, digest, ARRAY_SIZE(digest), &digest_len); - ssl_stream->SetPeerCertificateDigest(algorithm, digest, digest_len); - - // We no longer need our handle to the ssl stream. - ssl_stream_reference_.reset(); - LOG(LS_INFO) << "Connecting tunnel"; - // This will try to connect the PseudoTcpChannel. If and when that - // succeeds, then ssl negotiation will take place, and when that - // succeeds, the tunnel stream will finally open. - VERIFY(channel_->Connect( - content_name, "tcp", ICE_CANDIDATE_COMPONENT_DEFAULT)); -} - -} // namespace cricket diff --git a/webrtc/libjingle/session/tunnel/securetunnelsessionclient.h b/webrtc/libjingle/session/tunnel/securetunnelsessionclient.h deleted file mode 100644 index 5fa02522a..000000000 --- a/webrtc/libjingle/session/tunnel/securetunnelsessionclient.h +++ /dev/null @@ -1,165 +0,0 @@ -/* - * libjingle - * Copyright 2004--2008, 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. - */ - -// SecureTunnelSessionClient and SecureTunnelSession. -// SecureTunnelSessionClient extends TunnelSessionClient to exchange -// certificates as part of the session description. -// SecureTunnelSession is a TunnelSession that wraps the underlying -// tunnel stream into an SSLStreamAdapter. - -#ifndef WEBRTC_LIBJINGLE_SESSION_TUNNEL_SECURETUNNELSESSIONCLIENT_H_ -#define WEBRTC_LIBJINGLE_SESSION_TUNNEL_SECURETUNNELSESSIONCLIENT_H_ - -#include - -#include "webrtc/libjingle/session/tunnel/tunnelsessionclient.h" -#include "webrtc/base/sslidentity.h" -#include "webrtc/base/sslstreamadapter.h" - -namespace cricket { - -class SecureTunnelSession; // below - -// SecureTunnelSessionClient - -// This TunnelSessionClient establishes secure tunnels protected by -// SSL/TLS. The PseudoTcpChannel stream is wrapped with an -// SSLStreamAdapter. An SSLIdentity must be set or generated. -// -// The TunnelContentDescription is extended to include the client and -// server certificates. The initiator acts as the client. The session -// initiate stanza carries a description that contains the client's -// certificate, and the session accept response's description has the -// server certificate added to it. - -class SecureTunnelSessionClient : public TunnelSessionClient { - public: - // The jid is used as the name for sessions for outgoing tunnels. - // manager is the SessionManager to which we register this client - // and its sessions. - SecureTunnelSessionClient(const buzz::Jid& jid, SessionManager* manager); - - // Configures this client to use a preexisting SSLIdentity. - // The client takes ownership of the identity object. - // Use either SetIdentity or GenerateIdentity, and only once. - void SetIdentity(rtc::SSLIdentity* identity); - - // Generates an identity from nothing. - // Returns true if generation was successful. - // Use either SetIdentity or GenerateIdentity, and only once. - bool GenerateIdentity(); - - // Returns our identity for SSL purposes, as either set by - // SetIdentity() or generated by GenerateIdentity(). Call this - // method only after our identity has been successfully established - // by one of those methods. - rtc::SSLIdentity& GetIdentity() const; - - // Inherited methods - virtual void OnIncomingTunnel(const buzz::Jid& jid, Session *session); - virtual bool ParseContent(SignalingProtocol protocol, - const buzz::XmlElement* elem, - ContentDescription** content, - ParseError* error); - virtual bool WriteContent(SignalingProtocol protocol, - const ContentDescription* content, - buzz::XmlElement** elem, - WriteError* error); - virtual SessionDescription* CreateOffer( - const buzz::Jid &jid, const std::string &description); - virtual SessionDescription* CreateAnswer( - const SessionDescription* offer); - - protected: - virtual TunnelSession* MakeTunnelSession( - Session* session, rtc::Thread* stream_thread, - TunnelSessionRole role); - - private: - // Our identity (key and certificate) for SSL purposes. The - // certificate part will be communicated within the session - // description. The identity will be passed to the SSLStreamAdapter - // and used for SSL authentication. - rtc::scoped_ptr identity_; - - DISALLOW_COPY_AND_ASSIGN(SecureTunnelSessionClient); -}; - -// SecureTunnelSession: -// A TunnelSession represents one session for one client. It -// provides the actual tunnel stream and handles state changes. -// A SecureTunnelSession is a TunnelSession that wraps the underlying -// tunnel stream into an SSLStreamAdapter. - -class SecureTunnelSession : public TunnelSession { - public: - // This TunnelSession will tie together the given client and session. - // stream_thread is passed to the PseudoTCPChannel: it's the thread - // designated to interact with the tunnel stream. - // role is either INITIATOR or RESPONDER, depending on who is - // initiating the session. - SecureTunnelSession(SecureTunnelSessionClient* client, Session* session, - rtc::Thread* stream_thread, - TunnelSessionRole role); - - // Returns the stream that implements the actual P2P tunnel. - // This may be called only once. Caller is responsible for freeing - // the returned object. - virtual rtc::StreamInterface* GetStream(); - - protected: - // Inherited method: callback on accepting a session. - virtual void OnAccept(); - - // Helper method for GetStream() that Instantiates the - // SSLStreamAdapter to wrap the PseudoTcpChannel's stream, and - // configures it with our identity and role. - rtc::StreamInterface* MakeSecureStream( - rtc::StreamInterface* stream); - - // Our role in requesting the tunnel: INITIATOR or - // RESPONDER. Translates to our role in SSL negotiation: - // respectively client or server. Also indicates which slot of the - // SecureTunnelContentDescription our cert goes into: client-cert or - // server-cert respectively. - TunnelSessionRole role_; - - // This is the stream representing the usable tunnel endpoint. It's - // a StreamReference wrapping the SSLStreamAdapter instance, which - // further wraps a PseudoTcpChannel::InternalStream. The - // StreamReference is because in the case of CreateTunnel(), the - // stream endpoint is returned early, but we need to keep a handle - // on it so we can setup the peer certificate when we receive it - // later. - rtc::scoped_ptr ssl_stream_reference_; - - DISALLOW_COPY_AND_ASSIGN(SecureTunnelSession); -}; - -} // namespace cricket - -#endif // WEBRTC_LIBJINGLE_SESSION_TUNNEL_SECURETUNNELSESSIONCLIENT_H_ diff --git a/webrtc/libjingle/session/tunnel/tunnelsessionclient.cc b/webrtc/libjingle/session/tunnel/tunnelsessionclient.cc deleted file mode 100644 index 7d2a7d1d2..000000000 --- a/webrtc/libjingle/session/tunnel/tunnelsessionclient.cc +++ /dev/null @@ -1,432 +0,0 @@ -/* - * libjingle - * Copyright 2004--2008, 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 "pseudotcpchannel.h" -#include "webrtc/p2p/base/constants.h" -#include "webrtc/p2p/base/transportchannel.h" -#include "webrtc/libjingle/xmllite/xmlelement.h" -#include "tunnelsessionclient.h" -#include "webrtc/base/basicdefs.h" -#include "webrtc/base/basictypes.h" -#include "webrtc/base/common.h" -#include "webrtc/base/helpers.h" -#include "webrtc/base/logging.h" -#include "webrtc/base/stringutils.h" - -namespace cricket { - -const char NS_TUNNEL[] = "http://www.google.com/talk/tunnel"; -const buzz::StaticQName QN_TUNNEL_DESCRIPTION = { NS_TUNNEL, "description" }; -const buzz::StaticQName QN_TUNNEL_TYPE = { NS_TUNNEL, "type" }; -const char CN_TUNNEL[] = "tunnel"; - -enum { - MSG_CLOCK = 1, - MSG_DESTROY, - MSG_TERMINATE, - MSG_EVENT, - MSG_CREATE_TUNNEL, -}; - -struct EventData : public rtc::MessageData { - int event, error; - EventData(int ev, int err = 0) : event(ev), error(err) { } -}; - -struct CreateTunnelData : public rtc::MessageData { - buzz::Jid jid; - std::string description; - rtc::Thread* thread; - rtc::StreamInterface* stream; -}; - -extern const rtc::ConstantLabel SESSION_STATES[]; - -const rtc::ConstantLabel SESSION_STATES[] = { - KLABEL(Session::STATE_INIT), - KLABEL(Session::STATE_SENTINITIATE), - KLABEL(Session::STATE_RECEIVEDINITIATE), - KLABEL(Session::STATE_SENTACCEPT), - KLABEL(Session::STATE_RECEIVEDACCEPT), - KLABEL(Session::STATE_SENTMODIFY), - KLABEL(Session::STATE_RECEIVEDMODIFY), - KLABEL(Session::STATE_SENTREJECT), - KLABEL(Session::STATE_RECEIVEDREJECT), - KLABEL(Session::STATE_SENTREDIRECT), - KLABEL(Session::STATE_SENTTERMINATE), - KLABEL(Session::STATE_RECEIVEDTERMINATE), - KLABEL(Session::STATE_INPROGRESS), - KLABEL(Session::STATE_DEINIT), - LASTLABEL -}; - -/////////////////////////////////////////////////////////////////////////////// -// TunnelContentDescription -/////////////////////////////////////////////////////////////////////////////// - -struct TunnelContentDescription : public ContentDescription { - std::string description; - - TunnelContentDescription(const std::string& desc) : description(desc) { } - virtual ContentDescription* Copy() const { - return new TunnelContentDescription(*this); - } -}; - -/////////////////////////////////////////////////////////////////////////////// -// TunnelSessionClientBase -/////////////////////////////////////////////////////////////////////////////// - -TunnelSessionClientBase::TunnelSessionClientBase(const buzz::Jid& jid, - SessionManager* manager, const std::string &ns) - : jid_(jid), session_manager_(manager), namespace_(ns), shutdown_(false) { - session_manager_->AddClient(namespace_, this); -} - -TunnelSessionClientBase::~TunnelSessionClientBase() { - shutdown_ = true; - for (std::vector::iterator it = sessions_.begin(); - it != sessions_.end(); - ++it) { - Session* session = (*it)->ReleaseSession(true); - session_manager_->DestroySession(session); - } - session_manager_->RemoveClient(namespace_); -} - -void TunnelSessionClientBase::OnSessionCreate(Session* session, bool received) { - LOG(LS_INFO) << "TunnelSessionClientBase::OnSessionCreate: received=" - << received; - ASSERT(session_manager_->signaling_thread()->IsCurrent()); - if (received) - sessions_.push_back( - MakeTunnelSession(session, rtc::Thread::Current(), RESPONDER)); -} - -void TunnelSessionClientBase::OnSessionDestroy(Session* session) { - LOG(LS_INFO) << "TunnelSessionClientBase::OnSessionDestroy"; - ASSERT(session_manager_->signaling_thread()->IsCurrent()); - if (shutdown_) - return; - for (std::vector::iterator it = sessions_.begin(); - it != sessions_.end(); - ++it) { - if ((*it)->HasSession(session)) { - VERIFY((*it)->ReleaseSession(false) == session); - sessions_.erase(it); - return; - } - } -} - -rtc::StreamInterface* TunnelSessionClientBase::CreateTunnel( - const buzz::Jid& to, const std::string& description) { - // Valid from any thread - CreateTunnelData data; - data.jid = to; - data.description = description; - data.thread = rtc::Thread::Current(); - data.stream = NULL; - session_manager_->signaling_thread()->Send(this, MSG_CREATE_TUNNEL, &data); - return data.stream; -} - -rtc::StreamInterface* TunnelSessionClientBase::AcceptTunnel( - Session* session) { - ASSERT(session_manager_->signaling_thread()->IsCurrent()); - TunnelSession* tunnel = NULL; - for (std::vector::iterator it = sessions_.begin(); - it != sessions_.end(); - ++it) { - if ((*it)->HasSession(session)) { - tunnel = *it; - break; - } - } - ASSERT(tunnel != NULL); - - SessionDescription* answer = CreateAnswer(session->remote_description()); - if (answer == NULL) - return NULL; - - session->Accept(answer); - return tunnel->GetStream(); -} - -void TunnelSessionClientBase::DeclineTunnel(Session* session) { - ASSERT(session_manager_->signaling_thread()->IsCurrent()); - session->Reject(STR_TERMINATE_DECLINE); -} - -void TunnelSessionClientBase::OnMessage(rtc::Message* pmsg) { - if (pmsg->message_id == MSG_CREATE_TUNNEL) { - ASSERT(session_manager_->signaling_thread()->IsCurrent()); - CreateTunnelData* data = static_cast(pmsg->pdata); - SessionDescription* offer = CreateOffer(data->jid, data->description); - if (offer == NULL) { - return; - } - - Session* session = session_manager_->CreateSession(jid_.Str(), namespace_); - TunnelSession* tunnel = MakeTunnelSession(session, data->thread, - INITIATOR); - sessions_.push_back(tunnel); - session->Initiate(data->jid.Str(), offer); - data->stream = tunnel->GetStream(); - } -} - -TunnelSession* TunnelSessionClientBase::MakeTunnelSession( - Session* session, rtc::Thread* stream_thread, - TunnelSessionRole /*role*/) { - return new TunnelSession(this, session, stream_thread); -} - -/////////////////////////////////////////////////////////////////////////////// -// TunnelSessionClient -/////////////////////////////////////////////////////////////////////////////// - -TunnelSessionClient::TunnelSessionClient(const buzz::Jid& jid, - SessionManager* manager, - const std::string &ns) - : TunnelSessionClientBase(jid, manager, ns) { -} - -TunnelSessionClient::TunnelSessionClient(const buzz::Jid& jid, - SessionManager* manager) - : TunnelSessionClientBase(jid, manager, NS_TUNNEL) { -} - -TunnelSessionClient::~TunnelSessionClient() { -} - - -bool TunnelSessionClient::ParseContent(SignalingProtocol protocol, - const buzz::XmlElement* elem, - ContentDescription** content, - ParseError* error) { - if (const buzz::XmlElement* type_elem = elem->FirstNamed(QN_TUNNEL_TYPE)) { - *content = new TunnelContentDescription(type_elem->BodyText()); - return true; - } - return false; -} - -bool TunnelSessionClient::WriteContent( - SignalingProtocol protocol, - const ContentDescription* untyped_content, - buzz::XmlElement** elem, WriteError* error) { - const TunnelContentDescription* content = - static_cast(untyped_content); - - buzz::XmlElement* root = new buzz::XmlElement(QN_TUNNEL_DESCRIPTION, true); - buzz::XmlElement* type_elem = new buzz::XmlElement(QN_TUNNEL_TYPE); - type_elem->SetBodyText(content->description); - root->AddElement(type_elem); - *elem = root; - return true; -} - -SessionDescription* NewTunnelSessionDescription( - const std::string& content_name, ContentDescription* content) { - SessionDescription* sdesc = new SessionDescription(); - sdesc->AddContent(content_name, NS_TUNNEL, content); - return sdesc; -} - -bool FindTunnelContent(const cricket::SessionDescription* sdesc, - std::string* name, - const TunnelContentDescription** content) { - const ContentInfo* cinfo = sdesc->FirstContentByType(NS_TUNNEL); - if (cinfo == NULL) - return false; - - *name = cinfo->name; - *content = static_cast( - cinfo->description); - return true; -} - -void TunnelSessionClient::OnIncomingTunnel(const buzz::Jid &jid, - Session *session) { - std::string content_name; - const TunnelContentDescription* content = NULL; - if (!FindTunnelContent(session->remote_description(), - &content_name, &content)) { - session->Reject(STR_TERMINATE_INCOMPATIBLE_PARAMETERS); - return; - } - - SignalIncomingTunnel(this, jid, content->description, session); -} - -SessionDescription* TunnelSessionClient::CreateOffer( - const buzz::Jid &jid, const std::string &description) { - SessionDescription* offer = NewTunnelSessionDescription( - CN_TUNNEL, new TunnelContentDescription(description)); - rtc::scoped_ptr tdesc( - session_manager_->transport_desc_factory()->CreateOffer( - TransportOptions(), NULL)); - if (tdesc.get()) { - offer->AddTransportInfo(TransportInfo(CN_TUNNEL, *tdesc)); - } else { - delete offer; - offer = NULL; - } - return offer; -} - -SessionDescription* TunnelSessionClient::CreateAnswer( - const SessionDescription* offer) { - std::string content_name; - const TunnelContentDescription* offer_tunnel = NULL; - if (!FindTunnelContent(offer, &content_name, &offer_tunnel)) - return NULL; - - SessionDescription* answer = NewTunnelSessionDescription( - content_name, new TunnelContentDescription(offer_tunnel->description)); - const TransportInfo* tinfo = offer->GetTransportInfoByName(content_name); - if (tinfo) { - const TransportDescription* offer_tdesc = &tinfo->description; - ASSERT(offer_tdesc != NULL); - rtc::scoped_ptr tdesc( - session_manager_->transport_desc_factory()->CreateAnswer( - offer_tdesc, TransportOptions(), NULL)); - if (tdesc.get()) { - answer->AddTransportInfo(TransportInfo(content_name, *tdesc)); - } else { - delete answer; - answer = NULL; - } - } - return answer; -} -/////////////////////////////////////////////////////////////////////////////// -// TunnelSession -/////////////////////////////////////////////////////////////////////////////// - -// -// Signalling thread methods -// - -TunnelSession::TunnelSession(TunnelSessionClientBase* client, Session* session, - rtc::Thread* stream_thread) - : client_(client), session_(session), channel_(NULL) { - ASSERT(client_ != NULL); - ASSERT(session_ != NULL); - session_->SignalState.connect(this, &TunnelSession::OnSessionState); - channel_ = new PseudoTcpChannel(stream_thread, session_); - channel_->SignalChannelClosed.connect(this, &TunnelSession::OnChannelClosed); -} - -TunnelSession::~TunnelSession() { - ASSERT(client_ != NULL); - ASSERT(session_ == NULL); - ASSERT(channel_ == NULL); -} - -rtc::StreamInterface* TunnelSession::GetStream() { - ASSERT(channel_ != NULL); - return channel_->GetStream(); -} - -bool TunnelSession::HasSession(Session* session) { - ASSERT(NULL != session_); - return (session_ == session); -} - -Session* TunnelSession::ReleaseSession(bool channel_exists) { - ASSERT(NULL != session_); - ASSERT(NULL != channel_); - Session* session = session_; - session_->SignalState.disconnect(this); - session_ = NULL; - if (channel_exists) - channel_->SignalChannelClosed.disconnect(this); - channel_ = NULL; - delete this; - return session; -} - -void TunnelSession::OnSessionState(BaseSession* session, - BaseSession::State state) { - LOG(LS_INFO) << "TunnelSession::OnSessionState(" - << rtc::nonnull( - rtc::FindLabel(state, SESSION_STATES), "Unknown") - << ")"; - ASSERT(session == session_); - - switch (state) { - case Session::STATE_RECEIVEDINITIATE: - OnInitiate(); - break; - case Session::STATE_SENTACCEPT: - case Session::STATE_RECEIVEDACCEPT: - OnAccept(); - break; - case Session::STATE_SENTTERMINATE: - case Session::STATE_RECEIVEDTERMINATE: - OnTerminate(); - break; - case Session::STATE_DEINIT: - // ReleaseSession should have been called before this. - ASSERT(false); - break; - default: - break; - } -} - -void TunnelSession::OnInitiate() { - ASSERT(client_ != NULL); - ASSERT(session_ != NULL); - client_->OnIncomingTunnel(buzz::Jid(session_->remote_name()), session_); -} - -void TunnelSession::OnAccept() { - ASSERT(channel_ != NULL); - const ContentInfo* content = - session_->remote_description()->FirstContentByType(NS_TUNNEL); - ASSERT(content != NULL); - VERIFY(channel_->Connect( - content->name, "tcp", ICE_CANDIDATE_COMPONENT_DEFAULT)); -} - -void TunnelSession::OnTerminate() { - ASSERT(channel_ != NULL); - channel_->OnSessionTerminate(session_); -} - -void TunnelSession::OnChannelClosed(PseudoTcpChannel* channel) { - ASSERT(channel_ == channel); - ASSERT(session_ != NULL); - session_->Terminate(); -} - -/////////////////////////////////////////////////////////////////////////////// - -} // namespace cricket diff --git a/webrtc/libjingle/session/tunnel/tunnelsessionclient.h b/webrtc/libjingle/session/tunnel/tunnelsessionclient.h deleted file mode 100644 index 5fa121c15..000000000 --- a/webrtc/libjingle/session/tunnel/tunnelsessionclient.h +++ /dev/null @@ -1,182 +0,0 @@ -/* - * libjingle - * Copyright 2004--2008, 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 __TUNNELSESSIONCLIENT_H__ -#define __TUNNELSESSIONCLIENT_H__ - -#include - -#include "webrtc/base/criticalsection.h" -#include "webrtc/base/stream.h" -#include "webrtc/libjingle/session/sessionclient.h" -#include "webrtc/libjingle/session/sessionmanager.h" -#include "webrtc/libjingle/xmllite/qname.h" -#include "webrtc/libjingle/xmpp/constants.h" -#include "webrtc/p2p/base/constants.h" -#include "webrtc/p2p/base/pseudotcp.h" -#include "webrtc/p2p/base/session.h" -#include "webrtc/p2p/base/sessiondescription.h" - -namespace cricket { - -class TunnelSession; -class TunnelStream; - -enum TunnelSessionRole { INITIATOR, RESPONDER }; - -/////////////////////////////////////////////////////////////////////////////// -// TunnelSessionClient -/////////////////////////////////////////////////////////////////////////////// - -// Base class is still abstract -class TunnelSessionClientBase - : public SessionClient, public rtc::MessageHandler { -public: - TunnelSessionClientBase(const buzz::Jid& jid, SessionManager* manager, - const std::string &ns); - virtual ~TunnelSessionClientBase(); - - const buzz::Jid& jid() const { return jid_; } - SessionManager* session_manager() const { return session_manager_; } - - void OnSessionCreate(Session* session, bool received); - void OnSessionDestroy(Session* session); - - // This can be called on any thread. The stream interface is - // thread-safe, but notifications must be registered on the creating - // thread. - rtc::StreamInterface* CreateTunnel(const buzz::Jid& to, - const std::string& description); - - rtc::StreamInterface* AcceptTunnel(Session* session); - void DeclineTunnel(Session* session); - - // Invoked on an incoming tunnel - virtual void OnIncomingTunnel(const buzz::Jid &jid, Session *session) = 0; - - // Invoked on an outgoing session request - virtual SessionDescription* CreateOffer( - const buzz::Jid &jid, const std::string &description) = 0; - // Invoked on a session request accept to create - // the local-side session description - virtual SessionDescription* CreateAnswer( - const SessionDescription* offer) = 0; - -protected: - - void OnMessage(rtc::Message* pmsg); - - // helper method to instantiate TunnelSession. By overriding this, - // subclasses of TunnelSessionClient are able to instantiate - // subclasses of TunnelSession instead. - virtual TunnelSession* MakeTunnelSession(Session* session, - rtc::Thread* stream_thread, - TunnelSessionRole role); - - buzz::Jid jid_; - SessionManager* session_manager_; - std::vector sessions_; - std::string namespace_; - bool shutdown_; -}; - -class TunnelSessionClient - : public TunnelSessionClientBase, public sigslot::has_slots<> { -public: - TunnelSessionClient(const buzz::Jid& jid, SessionManager* manager); - TunnelSessionClient(const buzz::Jid& jid, SessionManager* manager, - const std::string &ns); - virtual ~TunnelSessionClient(); - - virtual bool ParseContent(SignalingProtocol protocol, - const buzz::XmlElement* elem, - ContentDescription** content, - ParseError* error); - virtual bool WriteContent(SignalingProtocol protocol, - const ContentDescription* content, - buzz::XmlElement** elem, - WriteError* error); - - // Signal arguments are this, initiator, description, session - sigslot::signal4 - SignalIncomingTunnel; - - virtual void OnIncomingTunnel(const buzz::Jid &jid, - Session *session); - virtual SessionDescription* CreateOffer( - const buzz::Jid &jid, const std::string &description); - virtual SessionDescription* CreateAnswer( - const SessionDescription* offer); -}; - -/////////////////////////////////////////////////////////////////////////////// -// TunnelSession -// Note: The lifetime of TunnelSession is complicated. It needs to survive -// until the following three conditions are true: -// 1) TunnelStream has called Close (tracked via non-null stream_) -// 2) PseudoTcp has completed (tracked via non-null tcp_) -// 3) Session has been destroyed (tracked via non-null session_) -// This is accomplished by calling CheckDestroy after these indicators change. -/////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// -// TunnelStream -// Note: Because TunnelStream provides a stream interface, its lifetime is -// controlled by the owner of the stream pointer. As a result, we must support -// both the TunnelSession disappearing before TunnelStream, and vice versa. -/////////////////////////////////////////////////////////////////////////////// - -class PseudoTcpChannel; - -class TunnelSession : public sigslot::has_slots<> { - public: - // Signalling thread methods - TunnelSession(TunnelSessionClientBase* client, Session* session, - rtc::Thread* stream_thread); - - virtual rtc::StreamInterface* GetStream(); - bool HasSession(Session* session); - Session* ReleaseSession(bool channel_exists); - - protected: - virtual ~TunnelSession(); - - virtual void OnSessionState(BaseSession* session, BaseSession::State state); - virtual void OnInitiate(); - virtual void OnAccept(); - virtual void OnTerminate(); - virtual void OnChannelClosed(PseudoTcpChannel* channel); - - TunnelSessionClientBase* client_; - Session* session_; - PseudoTcpChannel* channel_; -}; - -/////////////////////////////////////////////////////////////////////////////// - -} // namespace cricket - -#endif // __TUNNELSESSIONCLIENT_H__ diff --git a/webrtc/libjingle/session/tunnel/tunnelsessionclient_unittest.cc b/webrtc/libjingle/session/tunnel/tunnelsessionclient_unittest.cc deleted file mode 100644 index 97bfd848d..000000000 --- a/webrtc/libjingle/session/tunnel/tunnelsessionclient_unittest.cc +++ /dev/null @@ -1,226 +0,0 @@ -/* - * libjingle - * Copyright 2010, Google Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include "webrtc/base/gunit.h" -#include "webrtc/base/messagehandler.h" -#include "webrtc/base/scoped_ptr.h" -#include "webrtc/base/stream.h" -#include "webrtc/base/thread.h" -#include "webrtc/base/timeutils.h" -#include "webrtc/libjingle/session/sessionmanager.h" -#include "webrtc/libjingle/session/tunnel/tunnelsessionclient.h" -#include "webrtc/p2p/base/transport.h" -#include "webrtc/p2p/client/fakeportallocator.h" - -static const int kTimeoutMs = 10000; -static const int kBlockSize = 4096; -static const buzz::Jid kLocalJid("local@localhost"); -static const buzz::Jid kRemoteJid("remote@localhost"); - -// This test fixture creates the necessary plumbing to create and run -// two TunnelSessionClients that talk to each other. -class TunnelSessionClientTest : public testing::Test, - public rtc::MessageHandler, - public sigslot::has_slots<> { - public: - TunnelSessionClientTest() - : local_pa_(rtc::Thread::Current(), NULL), - remote_pa_(rtc::Thread::Current(), NULL), - local_sm_(&local_pa_, rtc::Thread::Current()), - remote_sm_(&remote_pa_, rtc::Thread::Current()), - local_client_(kLocalJid, &local_sm_), - remote_client_(kRemoteJid, &remote_sm_), - done_(false) { - local_sm_.SignalRequestSignaling.connect(this, - &TunnelSessionClientTest::OnLocalRequestSignaling); - local_sm_.SignalOutgoingMessage.connect(this, - &TunnelSessionClientTest::OnOutgoingMessage); - remote_sm_.SignalRequestSignaling.connect(this, - &TunnelSessionClientTest::OnRemoteRequestSignaling); - remote_sm_.SignalOutgoingMessage.connect(this, - &TunnelSessionClientTest::OnOutgoingMessage); - remote_client_.SignalIncomingTunnel.connect(this, - &TunnelSessionClientTest::OnIncomingTunnel); - } - - // Transfer the desired amount of data from the local to the remote client. - void TestTransfer(int size) { - // Create some dummy data to send. - send_stream_.ReserveSize(size); - for (int i = 0; i < size; ++i) { - char ch = static_cast(i); - send_stream_.Write(&ch, 1, NULL, NULL); - } - send_stream_.Rewind(); - // Prepare the receive stream. - recv_stream_.ReserveSize(size); - // Create the tunnel and set things in motion. - local_tunnel_.reset(local_client_.CreateTunnel(kRemoteJid, "test")); - local_tunnel_->SignalEvent.connect(this, - &TunnelSessionClientTest::OnStreamEvent); - EXPECT_TRUE_WAIT(done_, kTimeoutMs); - // Make sure we received the right data. - EXPECT_EQ(0, memcmp(send_stream_.GetBuffer(), - recv_stream_.GetBuffer(), size)); - } - - private: - enum { MSG_LSIGNAL, MSG_RSIGNAL }; - - // There's no SessionManager* argument in this callback, so we need 2 of them. - void OnLocalRequestSignaling() { - local_sm_.OnSignalingReady(); - } - void OnRemoteRequestSignaling() { - remote_sm_.OnSignalingReady(); - } - - // Post a message, to avoid problems with directly connecting the callbacks. - void OnOutgoingMessage(cricket::SessionManager* manager, - const buzz::XmlElement* stanza) { - if (manager == &local_sm_) { - rtc::Thread::Current()->Post(this, MSG_LSIGNAL, - rtc::WrapMessageData(*stanza)); - } else if (manager == &remote_sm_) { - rtc::Thread::Current()->Post(this, MSG_RSIGNAL, - rtc::WrapMessageData(*stanza)); - } - } - - // Need to add a "from=" attribute (normally added by the server) - // Then route the incoming signaling message to the "other" session manager. - virtual void OnMessage(rtc::Message* message) { - rtc::TypedMessageData* data = - static_cast*>( - message->pdata); - bool response = data->data().Attr(buzz::QN_TYPE) == buzz::STR_RESULT; - if (message->message_id == MSG_RSIGNAL) { - data->data().AddAttr(buzz::QN_FROM, remote_client_.jid().Str()); - if (!response) { - local_sm_.OnIncomingMessage(&data->data()); - } else { - local_sm_.OnIncomingResponse(NULL, &data->data()); - } - } else if (message->message_id == MSG_LSIGNAL) { - data->data().AddAttr(buzz::QN_FROM, local_client_.jid().Str()); - if (!response) { - remote_sm_.OnIncomingMessage(&data->data()); - } else { - remote_sm_.OnIncomingResponse(NULL, &data->data()); - } - } - delete data; - } - - // Accept the tunnel when it arrives and wire up the stream. - void OnIncomingTunnel(cricket::TunnelSessionClient* client, - buzz::Jid jid, std::string description, - cricket::Session* session) { - remote_tunnel_.reset(remote_client_.AcceptTunnel(session)); - remote_tunnel_->SignalEvent.connect(this, - &TunnelSessionClientTest::OnStreamEvent); - } - - // Send from send_stream_ as long as we're not flow-controlled. - // Read bytes out into recv_stream_ as they arrive. - // End the test when we are notified that the local side has closed the - // tunnel. All data has been read out at this point. - void OnStreamEvent(rtc::StreamInterface* stream, int events, - int error) { - if (events & rtc::SE_READ) { - if (stream == remote_tunnel_.get()) { - ReadData(); - } - } - if (events & rtc::SE_WRITE) { - if (stream == local_tunnel_.get()) { - bool done = false; - WriteData(&done); - if (done) { - local_tunnel_->Close(); - } - } - } - if (events & rtc::SE_CLOSE) { - if (stream == remote_tunnel_.get()) { - remote_tunnel_->Close(); - done_ = true; - } - } - } - - // Spool from the tunnel into recv_stream. - // Flow() doesn't work here because it won't write if the read blocks. - void ReadData() { - char block[kBlockSize]; - size_t read, position; - rtc::StreamResult res; - while ((res = remote_tunnel_->Read(block, sizeof(block), &read, NULL)) == - rtc::SR_SUCCESS) { - recv_stream_.Write(block, read, NULL, NULL); - } - ASSERT(res != rtc::SR_EOS); - recv_stream_.GetPosition(&position); - LOG(LS_VERBOSE) << "Recv position: " << position; - } - // Spool from send_stream into the tunnel. Back up if we get flow controlled. - void WriteData(bool* done) { - char block[kBlockSize]; - size_t leftover = 0, position; - rtc::StreamResult res = rtc::Flow(&send_stream_, - block, sizeof(block), local_tunnel_.get(), &leftover); - if (res == rtc::SR_BLOCK) { - send_stream_.GetPosition(&position); - send_stream_.SetPosition(position - leftover); - LOG(LS_VERBOSE) << "Send position: " << position - leftover; - *done = false; - } else if (res == rtc::SR_SUCCESS) { - *done = true; - } else { - ASSERT(false); // shouldn't happen - } - } - - private: - cricket::FakePortAllocator local_pa_; - cricket::FakePortAllocator remote_pa_; - cricket::SessionManager local_sm_; - cricket::SessionManager remote_sm_; - cricket::TunnelSessionClient local_client_; - cricket::TunnelSessionClient remote_client_; - rtc::scoped_ptr local_tunnel_; - rtc::scoped_ptr remote_tunnel_; - rtc::MemoryStream send_stream_; - rtc::MemoryStream recv_stream_; - bool done_; -}; - -// Test the normal case of sending data from one side to the other. -TEST_F(TunnelSessionClientTest, TestTransfer) { - TestTransfer(1000000); -}