git-svn-id: http://webrtc.googlecode.com/svn/trunk@7 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
parent
f0779a2582
commit
5c61233a88
66
third_party_mods/ace/LICENSE
Normal file
66
third_party_mods/ace/LICENSE
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
Copyright and Licensing Information for ACE(TM), TAO(TM), CIAO(TM), DAnCE(TM),
|
||||||
|
and CoSMIC(TM)
|
||||||
|
|
||||||
|
ACE(TM), TAO(TM), CIAO(TM), DAnCE>(TM), and CoSMIC(TM) (henceforth referred to
|
||||||
|
as "DOC software") are copyrighted by Douglas C. Schmidt and his research
|
||||||
|
group at Washington University, University of California, Irvine, and
|
||||||
|
Vanderbilt University, Copyright (c) 1993-2009, all rights reserved. Since DOC
|
||||||
|
software is open-source, freely available software, you are free to use,
|
||||||
|
modify, copy, and distribute--perpetually and irrevocably--the DOC software
|
||||||
|
source code and object code produced from the source, as well as copy and
|
||||||
|
distribute modified versions of this software. You must, however, include this
|
||||||
|
copyright statement along with any code built using DOC software that you
|
||||||
|
release. No copyright statement needs to be provided if you just ship binary
|
||||||
|
executables of your software products.
|
||||||
|
You can use DOC software in commercial and/or binary software releases and are
|
||||||
|
under no obligation to redistribute any of your source code that is built
|
||||||
|
using DOC software. Note, however, that you may not misappropriate the DOC
|
||||||
|
software code, such as copyrighting it yourself or claiming authorship of the
|
||||||
|
DOC software code, in a way that will prevent DOC software from being
|
||||||
|
distributed freely using an open-source development model. You needn't inform
|
||||||
|
anyone that you're using DOC software in your software, though we encourage
|
||||||
|
you to let us know so we can promote your project in the DOC software success
|
||||||
|
stories.
|
||||||
|
|
||||||
|
The ACE, TAO, CIAO, DAnCE, and CoSMIC web sites are maintained by the DOC
|
||||||
|
Group at the Institute for Software Integrated Systems (ISIS) and the Center
|
||||||
|
for Distributed Object Computing of Washington University, St. Louis for the
|
||||||
|
development of open-source software as part of the open-source software
|
||||||
|
community. Submissions are provided by the submitter ``as is'' with no
|
||||||
|
warranties whatsoever, including any warranty of merchantability,
|
||||||
|
noninfringement of third party intellectual property, or fitness for any
|
||||||
|
particular purpose. In no event shall the submitter be liable for any direct,
|
||||||
|
indirect, special, exemplary, punitive, or consequential damages, including
|
||||||
|
without limitation, lost profits, even if advised of the possibility of such
|
||||||
|
damages. Likewise, DOC software is provided as is with no warranties of any
|
||||||
|
kind, including the warranties of design, merchantability, and fitness for a
|
||||||
|
particular purpose, noninfringement, or arising from a course of dealing,
|
||||||
|
usage or trade practice. Washington University, UC Irvine, Vanderbilt
|
||||||
|
University, their employees, and students shall have no liability with respect
|
||||||
|
to the infringement of copyrights, trade secrets or any patents by DOC
|
||||||
|
software or any part thereof. Moreover, in no event will Washington
|
||||||
|
University, UC Irvine, or Vanderbilt University, their employees, or students
|
||||||
|
be liable for any lost revenue or profits or other special, indirect and
|
||||||
|
consequential damages.
|
||||||
|
|
||||||
|
DOC software is provided with no support and without any obligation on the
|
||||||
|
part of Washington University, UC Irvine, Vanderbilt University, their
|
||||||
|
employees, or students to assist in its use, correction, modification, or
|
||||||
|
enhancement. A number of companies around the world provide commercial support
|
||||||
|
for DOC software, however. DOC software is Y2K-compliant, as long as the
|
||||||
|
underlying OS platform is Y2K-compliant. Likewise, DOC software is compliant
|
||||||
|
with the new US daylight savings rule passed by Congress as "The Energy Policy
|
||||||
|
Act of 2005," which established new daylight savings times (DST) rules for the
|
||||||
|
United States that expand DST as of March 2007. Since DOC software obtains
|
||||||
|
time/date and calendaring information from operating systems users will not be
|
||||||
|
affected by the new DST rules as long as they upgrade their operating systems
|
||||||
|
accordingly.
|
||||||
|
|
||||||
|
The names ACE(TM), TAO(TM), CIAO(TM), DAnCE(TM), CoSMIC(TM), Washington
|
||||||
|
University, UC Irvine, and Vanderbilt University, may not be used to endorse
|
||||||
|
or promote products or services derived from this source without express
|
||||||
|
written permission from Washington University, UC Irvine, or Vanderbilt
|
||||||
|
University. This license grants no permission to call products or services
|
||||||
|
derived from this source ACE(TM), TAO(TM), CIAO(TM), DAnCE(TM), or CoSMIC(TM),
|
||||||
|
nor does it grant permission for the name Washington University, UC Irvine, or
|
||||||
|
Vanderbilt University to appear in their names.
|
||||||
27
third_party_mods/chromium/LICENSE
Normal file
27
third_party_mods/chromium/LICENSE
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
// Copyright (c) 2010 The Chromium Authors. All rights reserved.
|
||||||
|
//
|
||||||
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
// modification, are permitted provided that the following conditions are
|
||||||
|
// met:
|
||||||
|
//
|
||||||
|
// * Redistributions of source code must retain the above copyright
|
||||||
|
// notice, this list of conditions and the following disclaimer.
|
||||||
|
// * 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.
|
||||||
|
// * Neither the name of Google Inc. nor the names of its
|
||||||
|
// contributors may be used to endorse or promote products derived from
|
||||||
|
// this software without specific prior written permission.
|
||||||
|
//
|
||||||
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
// "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 COPYRIGHT
|
||||||
|
// OWNER OR CONTRIBUTORS 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.
|
||||||
42
third_party_mods/jsoncpp/jsoncpp.gyp
Normal file
42
third_party_mods/jsoncpp/jsoncpp.gyp
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
# Copyright (c) 2011 The Chromium Authors. All rights reserved.
|
||||||
|
# Use of this source code is governed by a BSD-style license that can be
|
||||||
|
# found in the LICENSE file.
|
||||||
|
|
||||||
|
{
|
||||||
|
'targets': [
|
||||||
|
{
|
||||||
|
'target_name': 'jsoncpp',
|
||||||
|
'type': '<(library)',
|
||||||
|
'sources': [
|
||||||
|
'include/json/autolink.h',
|
||||||
|
'include/json/config.h',
|
||||||
|
'include/json/forwards.h',
|
||||||
|
'include/json/json.h',
|
||||||
|
'include/json/reader.h',
|
||||||
|
'include/json/value.h',
|
||||||
|
'include/json/writer.h',
|
||||||
|
'src/lib_json/json_batchallocator.h',
|
||||||
|
'src/lib_json/json_internalarray.inl.h',
|
||||||
|
'src/lib_json/json_internalmap.inl.h',
|
||||||
|
'src/lib_json/json_reader.cpp',
|
||||||
|
'src/lib_json/json_value.cpp',
|
||||||
|
'src/lib_json/json_valueiterator.inl.h',
|
||||||
|
'src/lib_json/json_writer.cpp',
|
||||||
|
],
|
||||||
|
'include_dirs': [
|
||||||
|
'include/',
|
||||||
|
],
|
||||||
|
'direct_dependent_settings': {
|
||||||
|
'include_dirs': [
|
||||||
|
'include/',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
# Local Variables:
|
||||||
|
# tab-width:2
|
||||||
|
# indent-tabs-mode:nil
|
||||||
|
# End:
|
||||||
|
# vim: set expandtab tabstop=2 shiftwidth=2:
|
||||||
885
third_party_mods/jsoncpp/src/lib_json/json_reader.cpp
Normal file
885
third_party_mods/jsoncpp/src/lib_json/json_reader.cpp
Normal file
@ -0,0 +1,885 @@
|
|||||||
|
#include <json/reader.h>
|
||||||
|
#include <json/value.h>
|
||||||
|
#include <utility>
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cassert>
|
||||||
|
#include <cstring>
|
||||||
|
#include <iostream>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
#if _MSC_VER >= 1400 // VC++ 8.0
|
||||||
|
#pragma warning( disable : 4996 ) // disable warning about strdup being deprecated.
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace Json {
|
||||||
|
|
||||||
|
// Implementation of class Features
|
||||||
|
// ////////////////////////////////
|
||||||
|
|
||||||
|
Features::Features()
|
||||||
|
: allowComments_( true )
|
||||||
|
, strictRoot_( false )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Features
|
||||||
|
Features::all()
|
||||||
|
{
|
||||||
|
return Features();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Features
|
||||||
|
Features::strictMode()
|
||||||
|
{
|
||||||
|
Features features;
|
||||||
|
features.allowComments_ = false;
|
||||||
|
features.strictRoot_ = true;
|
||||||
|
return features;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implementation of class Reader
|
||||||
|
// ////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
static inline bool
|
||||||
|
in( Reader::Char c, Reader::Char c1, Reader::Char c2, Reader::Char c3, Reader::Char c4 )
|
||||||
|
{
|
||||||
|
return c == c1 || c == c2 || c == c3 || c == c4;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool
|
||||||
|
in( Reader::Char c, Reader::Char c1, Reader::Char c2, Reader::Char c3, Reader::Char c4, Reader::Char c5 )
|
||||||
|
{
|
||||||
|
return c == c1 || c == c2 || c == c3 || c == c4 || c == c5;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static bool
|
||||||
|
containsNewLine( Reader::Location begin,
|
||||||
|
Reader::Location end )
|
||||||
|
{
|
||||||
|
for ( ;begin < end; ++begin )
|
||||||
|
if ( *begin == '\n' || *begin == '\r' )
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string codePointToUTF8(unsigned int cp)
|
||||||
|
{
|
||||||
|
std::string result;
|
||||||
|
|
||||||
|
// based on description from http://en.wikipedia.org/wiki/UTF-8
|
||||||
|
|
||||||
|
if (cp <= 0x7f)
|
||||||
|
{
|
||||||
|
result.resize(1);
|
||||||
|
result[0] = static_cast<char>(cp);
|
||||||
|
}
|
||||||
|
else if (cp <= 0x7FF)
|
||||||
|
{
|
||||||
|
result.resize(2);
|
||||||
|
result[1] = static_cast<char>(0x80 | (0x3f & cp));
|
||||||
|
result[0] = static_cast<char>(0xC0 | (0x1f & (cp >> 6)));
|
||||||
|
}
|
||||||
|
else if (cp <= 0xFFFF)
|
||||||
|
{
|
||||||
|
result.resize(3);
|
||||||
|
result[2] = static_cast<char>(0x80 | (0x3f & cp));
|
||||||
|
result[1] = 0x80 | static_cast<char>((0x3f & (cp >> 6)));
|
||||||
|
result[0] = 0xE0 | static_cast<char>((0xf & (cp >> 12)));
|
||||||
|
}
|
||||||
|
else if (cp <= 0x10FFFF)
|
||||||
|
{
|
||||||
|
result.resize(4);
|
||||||
|
result[3] = static_cast<char>(0x80 | (0x3f & cp));
|
||||||
|
result[2] = static_cast<char>(0x80 | (0x3f & (cp >> 6)));
|
||||||
|
result[1] = static_cast<char>(0x80 | (0x3f & (cp >> 12)));
|
||||||
|
result[0] = static_cast<char>(0xF0 | (0x7 & (cp >> 18)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Class Reader
|
||||||
|
// //////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
Reader::Reader()
|
||||||
|
: features_( Features::all() )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Reader::Reader( const Features &features )
|
||||||
|
: features_( features )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
Reader::parse( const std::string &document,
|
||||||
|
Value &root,
|
||||||
|
bool collectComments )
|
||||||
|
{
|
||||||
|
document_ = document;
|
||||||
|
const char *begin = document_.c_str();
|
||||||
|
const char *end = begin + document_.length();
|
||||||
|
return parse( begin, end, root, collectComments );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
Reader::parse( std::istream& sin,
|
||||||
|
Value &root,
|
||||||
|
bool collectComments )
|
||||||
|
{
|
||||||
|
//std::istream_iterator<char> begin(sin);
|
||||||
|
//std::istream_iterator<char> end;
|
||||||
|
// Those would allow streamed input from a file, if parse() were a
|
||||||
|
// template function.
|
||||||
|
|
||||||
|
// Since std::string is reference-counted, this at least does not
|
||||||
|
// create an extra copy.
|
||||||
|
std::string doc;
|
||||||
|
std::getline(sin, doc, (char)EOF);
|
||||||
|
return parse( doc, root, collectComments );
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Reader::parse( const char *beginDoc, const char *endDoc,
|
||||||
|
Value &root,
|
||||||
|
bool collectComments )
|
||||||
|
{
|
||||||
|
if ( !features_.allowComments_ )
|
||||||
|
{
|
||||||
|
collectComments = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
begin_ = beginDoc;
|
||||||
|
end_ = endDoc;
|
||||||
|
collectComments_ = collectComments;
|
||||||
|
current_ = begin_;
|
||||||
|
lastValueEnd_ = 0;
|
||||||
|
lastValue_ = 0;
|
||||||
|
commentsBefore_ = "";
|
||||||
|
errors_.clear();
|
||||||
|
while ( !nodes_.empty() )
|
||||||
|
nodes_.pop();
|
||||||
|
nodes_.push( &root );
|
||||||
|
|
||||||
|
bool successful = readValue();
|
||||||
|
Token token;
|
||||||
|
skipCommentTokens( token );
|
||||||
|
if ( collectComments_ && !commentsBefore_.empty() )
|
||||||
|
root.setComment( commentsBefore_, commentAfter );
|
||||||
|
if ( features_.strictRoot_ )
|
||||||
|
{
|
||||||
|
if ( !root.isArray() && !root.isObject() )
|
||||||
|
{
|
||||||
|
// Set error location to start of doc, ideally should be first token found in doc
|
||||||
|
token.type_ = tokenError;
|
||||||
|
token.start_ = beginDoc;
|
||||||
|
token.end_ = endDoc;
|
||||||
|
addError( "A valid JSON document must be either an array or an object value.",
|
||||||
|
token );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return successful;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
Reader::readValue()
|
||||||
|
{
|
||||||
|
Token token;
|
||||||
|
skipCommentTokens( token );
|
||||||
|
bool successful = true;
|
||||||
|
|
||||||
|
if ( collectComments_ && !commentsBefore_.empty() )
|
||||||
|
{
|
||||||
|
currentValue().setComment( commentsBefore_, commentBefore );
|
||||||
|
commentsBefore_ = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
switch ( token.type_ )
|
||||||
|
{
|
||||||
|
case tokenObjectBegin:
|
||||||
|
successful = readObject( token );
|
||||||
|
break;
|
||||||
|
case tokenArrayBegin:
|
||||||
|
successful = readArray( token );
|
||||||
|
break;
|
||||||
|
case tokenNumber:
|
||||||
|
successful = decodeNumber( token );
|
||||||
|
break;
|
||||||
|
case tokenString:
|
||||||
|
successful = decodeString( token );
|
||||||
|
break;
|
||||||
|
case tokenTrue:
|
||||||
|
currentValue() = true;
|
||||||
|
break;
|
||||||
|
case tokenFalse:
|
||||||
|
currentValue() = false;
|
||||||
|
break;
|
||||||
|
case tokenNull:
|
||||||
|
currentValue() = Value();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return addError( "Syntax error: value, object or array expected.", token );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( collectComments_ )
|
||||||
|
{
|
||||||
|
lastValueEnd_ = current_;
|
||||||
|
lastValue_ = ¤tValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
return successful;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Reader::skipCommentTokens( Token &token )
|
||||||
|
{
|
||||||
|
if ( features_.allowComments_ )
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
readToken( token );
|
||||||
|
}
|
||||||
|
while ( token.type_ == tokenComment );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
readToken( token );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
Reader::expectToken( TokenType type, Token &token, const char *message )
|
||||||
|
{
|
||||||
|
readToken( token );
|
||||||
|
if ( token.type_ != type )
|
||||||
|
return addError( message, token );
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
Reader::readToken( Token &token )
|
||||||
|
{
|
||||||
|
skipSpaces();
|
||||||
|
token.start_ = current_;
|
||||||
|
Char c = getNextChar();
|
||||||
|
bool ok = true;
|
||||||
|
switch ( c )
|
||||||
|
{
|
||||||
|
case '{':
|
||||||
|
token.type_ = tokenObjectBegin;
|
||||||
|
break;
|
||||||
|
case '}':
|
||||||
|
token.type_ = tokenObjectEnd;
|
||||||
|
break;
|
||||||
|
case '[':
|
||||||
|
token.type_ = tokenArrayBegin;
|
||||||
|
break;
|
||||||
|
case ']':
|
||||||
|
token.type_ = tokenArrayEnd;
|
||||||
|
break;
|
||||||
|
case '"':
|
||||||
|
token.type_ = tokenString;
|
||||||
|
ok = readString();
|
||||||
|
break;
|
||||||
|
case '/':
|
||||||
|
token.type_ = tokenComment;
|
||||||
|
ok = readComment();
|
||||||
|
break;
|
||||||
|
case '0':
|
||||||
|
case '1':
|
||||||
|
case '2':
|
||||||
|
case '3':
|
||||||
|
case '4':
|
||||||
|
case '5':
|
||||||
|
case '6':
|
||||||
|
case '7':
|
||||||
|
case '8':
|
||||||
|
case '9':
|
||||||
|
case '-':
|
||||||
|
token.type_ = tokenNumber;
|
||||||
|
readNumber();
|
||||||
|
break;
|
||||||
|
case 't':
|
||||||
|
token.type_ = tokenTrue;
|
||||||
|
ok = match( "rue", 3 );
|
||||||
|
break;
|
||||||
|
case 'f':
|
||||||
|
token.type_ = tokenFalse;
|
||||||
|
ok = match( "alse", 4 );
|
||||||
|
break;
|
||||||
|
case 'n':
|
||||||
|
token.type_ = tokenNull;
|
||||||
|
ok = match( "ull", 3 );
|
||||||
|
break;
|
||||||
|
case ',':
|
||||||
|
token.type_ = tokenArraySeparator;
|
||||||
|
break;
|
||||||
|
case ':':
|
||||||
|
token.type_ = tokenMemberSeparator;
|
||||||
|
break;
|
||||||
|
case 0:
|
||||||
|
token.type_ = tokenEndOfStream;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ok = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if ( !ok )
|
||||||
|
token.type_ = tokenError;
|
||||||
|
token.end_ = current_;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Reader::skipSpaces()
|
||||||
|
{
|
||||||
|
while ( current_ != end_ )
|
||||||
|
{
|
||||||
|
Char c = *current_;
|
||||||
|
if ( c == ' ' || c == '\t' || c == '\r' || c == '\n' )
|
||||||
|
++current_;
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
Reader::match( Location pattern,
|
||||||
|
int patternLength )
|
||||||
|
{
|
||||||
|
if ( end_ - current_ < patternLength )
|
||||||
|
return false;
|
||||||
|
int index = patternLength;
|
||||||
|
while ( index-- )
|
||||||
|
if ( current_[index] != pattern[index] )
|
||||||
|
return false;
|
||||||
|
current_ += patternLength;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
Reader::readComment()
|
||||||
|
{
|
||||||
|
Location commentBegin = current_ - 1;
|
||||||
|
Char c = getNextChar();
|
||||||
|
bool successful = false;
|
||||||
|
if ( c == '*' )
|
||||||
|
successful = readCStyleComment();
|
||||||
|
else if ( c == '/' )
|
||||||
|
successful = readCppStyleComment();
|
||||||
|
if ( !successful )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if ( collectComments_ )
|
||||||
|
{
|
||||||
|
CommentPlacement placement = commentBefore;
|
||||||
|
if ( lastValueEnd_ && !containsNewLine( lastValueEnd_, commentBegin ) )
|
||||||
|
{
|
||||||
|
if ( c != '*' || !containsNewLine( commentBegin, current_ ) )
|
||||||
|
placement = commentAfterOnSameLine;
|
||||||
|
}
|
||||||
|
|
||||||
|
addComment( commentBegin, current_, placement );
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Reader::addComment( Location begin,
|
||||||
|
Location end,
|
||||||
|
CommentPlacement placement )
|
||||||
|
{
|
||||||
|
assert( collectComments_ );
|
||||||
|
if ( placement == commentAfterOnSameLine )
|
||||||
|
{
|
||||||
|
assert( lastValue_ != 0 );
|
||||||
|
lastValue_->setComment( std::string( begin, end ), placement );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ( !commentsBefore_.empty() )
|
||||||
|
commentsBefore_ += "\n";
|
||||||
|
commentsBefore_ += std::string( begin, end );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
Reader::readCStyleComment()
|
||||||
|
{
|
||||||
|
while ( current_ != end_ )
|
||||||
|
{
|
||||||
|
Char c = getNextChar();
|
||||||
|
if ( c == '*' && *current_ == '/' )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return getNextChar() == '/';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
Reader::readCppStyleComment()
|
||||||
|
{
|
||||||
|
while ( current_ != end_ )
|
||||||
|
{
|
||||||
|
Char c = getNextChar();
|
||||||
|
if ( c == '\r' || c == '\n' )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Reader::readNumber()
|
||||||
|
{
|
||||||
|
while ( current_ != end_ )
|
||||||
|
{
|
||||||
|
if ( !(*current_ >= '0' && *current_ <= '9') &&
|
||||||
|
!in( *current_, '.', 'e', 'E', '+', '-' ) )
|
||||||
|
break;
|
||||||
|
++current_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Reader::readString()
|
||||||
|
{
|
||||||
|
Char c = 0;
|
||||||
|
while ( current_ != end_ )
|
||||||
|
{
|
||||||
|
c = getNextChar();
|
||||||
|
if ( c == '\\' )
|
||||||
|
getNextChar();
|
||||||
|
else if ( c == '"' )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return c == '"';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
Reader::readObject( Token &tokenStart )
|
||||||
|
{
|
||||||
|
Token tokenName;
|
||||||
|
std::string name;
|
||||||
|
currentValue() = Value( objectValue );
|
||||||
|
while ( readToken( tokenName ) )
|
||||||
|
{
|
||||||
|
bool initialTokenOk = true;
|
||||||
|
while ( tokenName.type_ == tokenComment && initialTokenOk )
|
||||||
|
initialTokenOk = readToken( tokenName );
|
||||||
|
if ( !initialTokenOk )
|
||||||
|
break;
|
||||||
|
if ( tokenName.type_ == tokenObjectEnd && name.empty() ) // empty object
|
||||||
|
return true;
|
||||||
|
if ( tokenName.type_ != tokenString )
|
||||||
|
break;
|
||||||
|
|
||||||
|
name = "";
|
||||||
|
if ( !decodeString( tokenName, name ) )
|
||||||
|
return recoverFromError( tokenObjectEnd );
|
||||||
|
|
||||||
|
Token colon;
|
||||||
|
if ( !readToken( colon ) || colon.type_ != tokenMemberSeparator )
|
||||||
|
{
|
||||||
|
return addErrorAndRecover( "Missing ':' after object member name",
|
||||||
|
colon,
|
||||||
|
tokenObjectEnd );
|
||||||
|
}
|
||||||
|
Value &value = currentValue()[ name ];
|
||||||
|
nodes_.push( &value );
|
||||||
|
bool ok = readValue();
|
||||||
|
nodes_.pop();
|
||||||
|
if ( !ok ) // error already set
|
||||||
|
return recoverFromError( tokenObjectEnd );
|
||||||
|
|
||||||
|
Token comma;
|
||||||
|
if ( !readToken( comma )
|
||||||
|
|| ( comma.type_ != tokenObjectEnd &&
|
||||||
|
comma.type_ != tokenArraySeparator &&
|
||||||
|
comma.type_ != tokenComment ) )
|
||||||
|
{
|
||||||
|
return addErrorAndRecover( "Missing ',' or '}' in object declaration",
|
||||||
|
comma,
|
||||||
|
tokenObjectEnd );
|
||||||
|
}
|
||||||
|
bool finalizeTokenOk = true;
|
||||||
|
while ( comma.type_ == tokenComment &&
|
||||||
|
finalizeTokenOk )
|
||||||
|
finalizeTokenOk = readToken( comma );
|
||||||
|
if ( comma.type_ == tokenObjectEnd )
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return addErrorAndRecover( "Missing '}' or object member name",
|
||||||
|
tokenName,
|
||||||
|
tokenObjectEnd );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
Reader::readArray( Token &tokenStart )
|
||||||
|
{
|
||||||
|
currentValue() = Value( arrayValue );
|
||||||
|
skipSpaces();
|
||||||
|
if ( *current_ == ']' ) // empty array
|
||||||
|
{
|
||||||
|
Token endArray;
|
||||||
|
readToken( endArray );
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
int index = 0;
|
||||||
|
while ( true )
|
||||||
|
{
|
||||||
|
Value &value = currentValue()[ index++ ];
|
||||||
|
nodes_.push( &value );
|
||||||
|
bool ok = readValue();
|
||||||
|
nodes_.pop();
|
||||||
|
if ( !ok ) // error already set
|
||||||
|
return recoverFromError( tokenArrayEnd );
|
||||||
|
|
||||||
|
Token token;
|
||||||
|
// Accept Comment after last item in the array.
|
||||||
|
ok = readToken( token );
|
||||||
|
while ( token.type_ == tokenComment && ok )
|
||||||
|
{
|
||||||
|
ok = readToken( token );
|
||||||
|
}
|
||||||
|
bool badTokenType = ( token.type_ == tokenArraySeparator &&
|
||||||
|
token.type_ == tokenArrayEnd );
|
||||||
|
if ( !ok || badTokenType )
|
||||||
|
{
|
||||||
|
return addErrorAndRecover( "Missing ',' or ']' in array declaration",
|
||||||
|
token,
|
||||||
|
tokenArrayEnd );
|
||||||
|
}
|
||||||
|
if ( token.type_ == tokenArrayEnd )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
Reader::decodeNumber( Token &token )
|
||||||
|
{
|
||||||
|
bool isDouble = false;
|
||||||
|
for ( Location inspect = token.start_; inspect != token.end_; ++inspect )
|
||||||
|
{
|
||||||
|
isDouble = isDouble
|
||||||
|
|| in( *inspect, '.', 'e', 'E', '+' )
|
||||||
|
|| ( *inspect == '-' && inspect != token.start_ );
|
||||||
|
}
|
||||||
|
if ( isDouble )
|
||||||
|
return decodeDouble( token );
|
||||||
|
Location current = token.start_;
|
||||||
|
bool isNegative = *current == '-';
|
||||||
|
if ( isNegative )
|
||||||
|
++current;
|
||||||
|
Value::UInt threshold = (isNegative ? Value::UInt(-Value::minInt)
|
||||||
|
: Value::maxUInt) / 10;
|
||||||
|
Value::UInt value = 0;
|
||||||
|
while ( current < token.end_ )
|
||||||
|
{
|
||||||
|
Char c = *current++;
|
||||||
|
if ( c < '0' || c > '9' )
|
||||||
|
return addError( "'" + std::string( token.start_, token.end_ ) + "' is not a number.", token );
|
||||||
|
if ( value >= threshold )
|
||||||
|
return decodeDouble( token );
|
||||||
|
value = value * 10 + Value::UInt(c - '0');
|
||||||
|
}
|
||||||
|
if ( isNegative )
|
||||||
|
currentValue() = -Value::Int( value );
|
||||||
|
else if ( value <= Value::UInt(Value::maxInt) )
|
||||||
|
currentValue() = Value::Int( value );
|
||||||
|
else
|
||||||
|
currentValue() = value;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
Reader::decodeDouble( Token &token )
|
||||||
|
{
|
||||||
|
double value = 0;
|
||||||
|
const int bufferSize = 32;
|
||||||
|
int count;
|
||||||
|
int length = int(token.end_ - token.start_);
|
||||||
|
if ( length <= bufferSize )
|
||||||
|
{
|
||||||
|
Char buffer[bufferSize];
|
||||||
|
memcpy( buffer, token.start_, length );
|
||||||
|
buffer[length] = 0;
|
||||||
|
count = sscanf( buffer, "%lf", &value );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::string buffer( token.start_, token.end_ );
|
||||||
|
count = sscanf( buffer.c_str(), "%lf", &value );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( count != 1 )
|
||||||
|
return addError( "'" + std::string( token.start_, token.end_ ) + "' is not a number.", token );
|
||||||
|
currentValue() = value;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
Reader::decodeString( Token &token )
|
||||||
|
{
|
||||||
|
std::string decoded;
|
||||||
|
if ( !decodeString( token, decoded ) )
|
||||||
|
return false;
|
||||||
|
currentValue() = decoded;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
Reader::decodeString( Token &token, std::string &decoded )
|
||||||
|
{
|
||||||
|
decoded.reserve( token.end_ - token.start_ - 2 );
|
||||||
|
Location current = token.start_ + 1; // skip '"'
|
||||||
|
Location end = token.end_ - 1; // do not include '"'
|
||||||
|
while ( current != end )
|
||||||
|
{
|
||||||
|
Char c = *current++;
|
||||||
|
if ( c == '"' )
|
||||||
|
break;
|
||||||
|
else if ( c == '\\' )
|
||||||
|
{
|
||||||
|
if ( current == end )
|
||||||
|
return addError( "Empty escape sequence in string", token, current );
|
||||||
|
Char escape = *current++;
|
||||||
|
switch ( escape )
|
||||||
|
{
|
||||||
|
case '"': decoded += '"'; break;
|
||||||
|
case '/': decoded += '/'; break;
|
||||||
|
case '\\': decoded += '\\'; break;
|
||||||
|
case 'b': decoded += '\b'; break;
|
||||||
|
case 'f': decoded += '\f'; break;
|
||||||
|
case 'n': decoded += '\n'; break;
|
||||||
|
case 'r': decoded += '\r'; break;
|
||||||
|
case 't': decoded += '\t'; break;
|
||||||
|
case 'u':
|
||||||
|
{
|
||||||
|
unsigned int unicode;
|
||||||
|
if ( !decodeUnicodeCodePoint( token, current, end, unicode ) )
|
||||||
|
return false;
|
||||||
|
decoded += codePointToUTF8(unicode);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return addError( "Bad escape sequence in string", token, current );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
decoded += c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Reader::decodeUnicodeCodePoint( Token &token,
|
||||||
|
Location ¤t,
|
||||||
|
Location end,
|
||||||
|
unsigned int &unicode )
|
||||||
|
{
|
||||||
|
|
||||||
|
if ( !decodeUnicodeEscapeSequence( token, current, end, unicode ) )
|
||||||
|
return false;
|
||||||
|
if (unicode >= 0xD800 && unicode <= 0xDBFF)
|
||||||
|
{
|
||||||
|
// surrogate pairs
|
||||||
|
if (end - current < 6)
|
||||||
|
return addError( "additional six characters expected to parse unicode surrogate pair.", token, current );
|
||||||
|
unsigned int surrogatePair;
|
||||||
|
if (*(current++) == '\\' && *(current++)== 'u')
|
||||||
|
{
|
||||||
|
if (decodeUnicodeEscapeSequence( token, current, end, surrogatePair ))
|
||||||
|
{
|
||||||
|
unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return addError( "expecting another \\u token to begin the second half of a unicode surrogate pair", token, current );
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Reader::decodeUnicodeEscapeSequence( Token &token,
|
||||||
|
Location ¤t,
|
||||||
|
Location end,
|
||||||
|
unsigned int &unicode )
|
||||||
|
{
|
||||||
|
if ( end - current < 4 )
|
||||||
|
return addError( "Bad unicode escape sequence in string: four digits expected.", token, current );
|
||||||
|
unicode = 0;
|
||||||
|
for ( int index =0; index < 4; ++index )
|
||||||
|
{
|
||||||
|
Char c = *current++;
|
||||||
|
unicode *= 16;
|
||||||
|
if ( c >= '0' && c <= '9' )
|
||||||
|
unicode += c - '0';
|
||||||
|
else if ( c >= 'a' && c <= 'f' )
|
||||||
|
unicode += c - 'a' + 10;
|
||||||
|
else if ( c >= 'A' && c <= 'F' )
|
||||||
|
unicode += c - 'A' + 10;
|
||||||
|
else
|
||||||
|
return addError( "Bad unicode escape sequence in string: hexadecimal digit expected.", token, current );
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
Reader::addError( const std::string &message,
|
||||||
|
Token &token,
|
||||||
|
Location extra )
|
||||||
|
{
|
||||||
|
ErrorInfo info;
|
||||||
|
info.token_ = token;
|
||||||
|
info.message_ = message;
|
||||||
|
info.extra_ = extra;
|
||||||
|
errors_.push_back( info );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
Reader::recoverFromError( TokenType skipUntilToken )
|
||||||
|
{
|
||||||
|
int errorCount = int(errors_.size());
|
||||||
|
Token skip;
|
||||||
|
while ( true )
|
||||||
|
{
|
||||||
|
if ( !readToken(skip) )
|
||||||
|
errors_.resize( errorCount ); // discard errors caused by recovery
|
||||||
|
if ( skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
errors_.resize( errorCount );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
Reader::addErrorAndRecover( const std::string &message,
|
||||||
|
Token &token,
|
||||||
|
TokenType skipUntilToken )
|
||||||
|
{
|
||||||
|
addError( message, token );
|
||||||
|
return recoverFromError( skipUntilToken );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Value &
|
||||||
|
Reader::currentValue()
|
||||||
|
{
|
||||||
|
return *(nodes_.top());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Reader::Char
|
||||||
|
Reader::getNextChar()
|
||||||
|
{
|
||||||
|
if ( current_ == end_ )
|
||||||
|
return 0;
|
||||||
|
return *current_++;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Reader::getLocationLineAndColumn( Location location,
|
||||||
|
int &line,
|
||||||
|
int &column ) const
|
||||||
|
{
|
||||||
|
Location current = begin_;
|
||||||
|
Location lastLineStart = current;
|
||||||
|
line = 0;
|
||||||
|
while ( current < location && current != end_ )
|
||||||
|
{
|
||||||
|
Char c = *current++;
|
||||||
|
if ( c == '\r' )
|
||||||
|
{
|
||||||
|
if ( *current == '\n' )
|
||||||
|
++current;
|
||||||
|
lastLineStart = current;
|
||||||
|
++line;
|
||||||
|
}
|
||||||
|
else if ( c == '\n' )
|
||||||
|
{
|
||||||
|
lastLineStart = current;
|
||||||
|
++line;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// column & line start at 1
|
||||||
|
column = int(location - lastLineStart) + 1;
|
||||||
|
++line;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::string
|
||||||
|
Reader::getLocationLineAndColumn( Location location ) const
|
||||||
|
{
|
||||||
|
int line, column;
|
||||||
|
getLocationLineAndColumn( location, line, column );
|
||||||
|
char buffer[18+16+16+1];
|
||||||
|
sprintf( buffer, "Line %d, Column %d", line, column );
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::string
|
||||||
|
Reader::getFormatedErrorMessages() const
|
||||||
|
{
|
||||||
|
std::string formattedMessage;
|
||||||
|
for ( Errors::const_iterator itError = errors_.begin();
|
||||||
|
itError != errors_.end();
|
||||||
|
++itError )
|
||||||
|
{
|
||||||
|
const ErrorInfo &error = *itError;
|
||||||
|
formattedMessage += "* " + getLocationLineAndColumn( error.token_.start_ ) + "\n";
|
||||||
|
formattedMessage += " " + error.message_ + "\n";
|
||||||
|
if ( error.extra_ )
|
||||||
|
formattedMessage += "See " + getLocationLineAndColumn( error.extra_ ) + " for detail.\n";
|
||||||
|
}
|
||||||
|
return formattedMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::istream& operator>>( std::istream &sin, Value &root )
|
||||||
|
{
|
||||||
|
Json::Reader reader;
|
||||||
|
bool ok = reader.parse(sin, root, true);
|
||||||
|
//JSON_ASSERT( ok );
|
||||||
|
//if (!ok) throw std::runtime_error(reader.getFormatedErrorMessages());
|
||||||
|
return sin;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace Json
|
||||||
1718
third_party_mods/jsoncpp/src/lib_json/json_value.cpp
Normal file
1718
third_party_mods/jsoncpp/src/lib_json/json_value.cpp
Normal file
File diff suppressed because it is too large
Load Diff
639
third_party_mods/libjingle/libjingle.gyp
Normal file
639
third_party_mods/libjingle/libjingle.gyp
Normal file
@ -0,0 +1,639 @@
|
|||||||
|
# Copyright (c) 2011 The Chromium Authors. All rights reserved.
|
||||||
|
# Use of this source code is governed by a BSD-style license that can be
|
||||||
|
# found in the LICENSE file.
|
||||||
|
|
||||||
|
{
|
||||||
|
'variables': {
|
||||||
|
# Chromium targets will have set inside_chromium_build to 1.
|
||||||
|
# We declare a default value of 0 for standalone builds.
|
||||||
|
'inside_chromium_build%': 0,
|
||||||
|
'no_libjingle_logging%': 0,
|
||||||
|
},
|
||||||
|
'target_defaults': {
|
||||||
|
'defines': [
|
||||||
|
'FEATURE_ENABLE_SSL',
|
||||||
|
'FEATURE_ENABLE_VOICEMAIL', # TODO(ncarter): Do we really need this?
|
||||||
|
'_USE_32BIT_TIME_T',
|
||||||
|
'SAFE_TO_DEFINE_TALK_BASE_LOGGING_MACROS',
|
||||||
|
'EXPAT_RELATIVE_PATH',
|
||||||
|
'HAVE_WEBRTC',
|
||||||
|
],
|
||||||
|
'configurations': {
|
||||||
|
'Debug': {
|
||||||
|
'defines': [
|
||||||
|
# TODO(sergeyu): Fix libjingle to use NDEBUG instead of
|
||||||
|
# _DEBUG and remove this define. See below as well.
|
||||||
|
'_DEBUG',
|
||||||
|
],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'dependencies': [
|
||||||
|
'../expat/expat.gyp:expat',
|
||||||
|
],
|
||||||
|
'direct_dependent_settings': {
|
||||||
|
'defines': [
|
||||||
|
'FEATURE_ENABLE_SSL',
|
||||||
|
'FEATURE_ENABLE_VOICEMAIL',
|
||||||
|
'EXPAT_RELATIVE_PATH',
|
||||||
|
],
|
||||||
|
'conditions': [
|
||||||
|
['OS=="win"', {
|
||||||
|
'link_settings': {
|
||||||
|
'libraries': [
|
||||||
|
'-lsecur32.lib',
|
||||||
|
'-lcrypt32.lib',
|
||||||
|
'-liphlpapi.lib',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
}],
|
||||||
|
['OS=="win"', {
|
||||||
|
'include_dirs': [
|
||||||
|
'../third_party/platformsdk_win7/files/Include',
|
||||||
|
],
|
||||||
|
'defines': [
|
||||||
|
'_CRT_SECURE_NO_WARNINGS', # Suppres warnings about _vsnprinf
|
||||||
|
],
|
||||||
|
}],
|
||||||
|
['OS=="linux"', {
|
||||||
|
'defines': [
|
||||||
|
'LINUX',
|
||||||
|
],
|
||||||
|
}],
|
||||||
|
['OS=="mac"', {
|
||||||
|
'defines': [
|
||||||
|
'OSX',
|
||||||
|
],
|
||||||
|
}],
|
||||||
|
['OS=="linux" or OS=="mac" or OS=="freebsd" or OS=="openbsd"', {
|
||||||
|
'defines': [
|
||||||
|
'POSIX',
|
||||||
|
],
|
||||||
|
}],
|
||||||
|
['OS=="openbsd" or OS=="freebsd"', {
|
||||||
|
'defines': [
|
||||||
|
'BSD',
|
||||||
|
],
|
||||||
|
}],
|
||||||
|
['no_libjingle_logging==1', {
|
||||||
|
'defines': [
|
||||||
|
'NO_LIBJINGLE_LOGGING',
|
||||||
|
],
|
||||||
|
}],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
'all_dependent_settings': {
|
||||||
|
'configurations': {
|
||||||
|
'Debug': {
|
||||||
|
'defines': [
|
||||||
|
# TODO(sergeyu): Fix libjingle to use NDEBUG instead of
|
||||||
|
# _DEBUG and remove this define. See above as well.
|
||||||
|
'_DEBUG',
|
||||||
|
],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'conditions': [
|
||||||
|
['inside_chromium_build==1', {
|
||||||
|
'include_dirs': [
|
||||||
|
'./overrides',
|
||||||
|
'../..', # the third_party folder for webrtc includes
|
||||||
|
'./source',
|
||||||
|
'../../third_party/expat/files',
|
||||||
|
],
|
||||||
|
'direct_dependent_settings': {
|
||||||
|
'include_dirs': [
|
||||||
|
'./overrides',
|
||||||
|
'./source',
|
||||||
|
'../../third_party/expat/files'
|
||||||
|
],
|
||||||
|
},
|
||||||
|
'dependencies': [
|
||||||
|
'../../base/base.gyp:base',
|
||||||
|
'../../net/net.gyp:net',
|
||||||
|
],
|
||||||
|
},{
|
||||||
|
'include_dirs': [
|
||||||
|
# the third_party folder for webrtc/ includes (non-chromium).
|
||||||
|
'../../trunk',
|
||||||
|
'./source',
|
||||||
|
'../../third_party/expat/files',
|
||||||
|
],
|
||||||
|
}],
|
||||||
|
['OS=="win"', {
|
||||||
|
'include_dirs': [
|
||||||
|
'../third_party/platformsdk_win7/files/Include',
|
||||||
|
],
|
||||||
|
}],
|
||||||
|
['OS=="linux"', {
|
||||||
|
'defines': [
|
||||||
|
'LINUX',
|
||||||
|
],
|
||||||
|
}],
|
||||||
|
['OS=="mac"', {
|
||||||
|
'defines': [
|
||||||
|
'OSX',
|
||||||
|
],
|
||||||
|
}],
|
||||||
|
['OS=="linux" or OS=="mac" or OS=="freebsd" or OS=="openbsd"', {
|
||||||
|
'defines': [
|
||||||
|
'POSIX',
|
||||||
|
],
|
||||||
|
}],
|
||||||
|
['OS=="openbsd" or OS=="freebsd"', {
|
||||||
|
'defines': [
|
||||||
|
'BSD',
|
||||||
|
],
|
||||||
|
}],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
'targets': [
|
||||||
|
{
|
||||||
|
'target_name': 'libjingle',
|
||||||
|
'variables': {
|
||||||
|
'conditions': [
|
||||||
|
['inside_chromium_build==1', {
|
||||||
|
'overrides': 'overrides',
|
||||||
|
},{
|
||||||
|
'overrides': 'source',
|
||||||
|
}],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
'type': '<(library)',
|
||||||
|
'sources': [
|
||||||
|
'<(overrides)/talk/base/basictypes.h',
|
||||||
|
'<(overrides)/talk/base/constructormagic.h',
|
||||||
|
|
||||||
|
# Need to override logging.h because we need
|
||||||
|
# SAFE_TO_DEFINE_TALK_BASE_LOGGING_MACROS to work.
|
||||||
|
# TODO(sergeyu): push SAFE_TO_DEFINE_TALK_BASE_LOGGING_MACROS to
|
||||||
|
# libjingle and remove this override.
|
||||||
|
'<(overrides)/talk/base/logging.h',
|
||||||
|
|
||||||
|
'<(overrides)/talk/base/scoped_ptr.h',
|
||||||
|
|
||||||
|
# Libjingle's QName is not threadsafe, so we need to use our own version
|
||||||
|
# here.
|
||||||
|
# TODO(sergeyu): Fix QName in Libjingle.
|
||||||
|
'<(overrides)/talk/xmllite/qname.cc',
|
||||||
|
'<(overrides)/talk/xmllite/qname.h',
|
||||||
|
|
||||||
|
'source/talk/base/Equifax_Secure_Global_eBusiness_CA-1.h',
|
||||||
|
'source/talk/base/asyncfile.cc',
|
||||||
|
'source/talk/base/asyncfile.h',
|
||||||
|
'source/talk/base/asynchttprequest.cc',
|
||||||
|
'source/talk/base/asynchttprequest.h',
|
||||||
|
'source/talk/base/asyncpacketsocket.h',
|
||||||
|
'source/talk/base/asyncsocket.cc',
|
||||||
|
'source/talk/base/asyncsocket.h',
|
||||||
|
'source/talk/base/asynctcpsocket.cc',
|
||||||
|
'source/talk/base/asynctcpsocket.h',
|
||||||
|
'source/talk/base/asyncudpsocket.cc',
|
||||||
|
'source/talk/base/asyncudpsocket.h',
|
||||||
|
'source/talk/base/autodetectproxy.cc',
|
||||||
|
'source/talk/base/autodetectproxy.h',
|
||||||
|
'source/talk/base/base64.cc',
|
||||||
|
'source/talk/base/base64.h',
|
||||||
|
'source/talk/base/basicdefs.h',
|
||||||
|
'source/talk/base/basicpacketsocketfactory.cc',
|
||||||
|
'source/talk/base/basicpacketsocketfactory.h',
|
||||||
|
'source/talk/base/bytebuffer.cc',
|
||||||
|
'source/talk/base/bytebuffer.h',
|
||||||
|
'source/talk/base/byteorder.h',
|
||||||
|
'source/talk/base/checks.cc',
|
||||||
|
'source/talk/base/checks.h',
|
||||||
|
'source/talk/base/common.cc',
|
||||||
|
'source/talk/base/common.h',
|
||||||
|
'source/talk/base/criticalsection.h',
|
||||||
|
'source/talk/base/cryptstring.h',
|
||||||
|
'source/talk/base/diskcache.cc',
|
||||||
|
'source/talk/base/diskcache.h',
|
||||||
|
'source/talk/base/event.cc',
|
||||||
|
'source/talk/base/event.h',
|
||||||
|
'source/talk/base/fileutils.cc',
|
||||||
|
'source/talk/base/fileutils.h',
|
||||||
|
'source/talk/base/firewallsocketserver.cc',
|
||||||
|
'source/talk/base/firewallsocketserver.h',
|
||||||
|
'source/talk/base/flags.cc',
|
||||||
|
'source/talk/base/flags.h',
|
||||||
|
'source/talk/base/helpers.cc',
|
||||||
|
'source/talk/base/helpers.h',
|
||||||
|
'source/talk/base/host.cc',
|
||||||
|
'source/talk/base/host.h',
|
||||||
|
'source/talk/base/httpbase.cc',
|
||||||
|
'source/talk/base/httpbase.h',
|
||||||
|
'source/talk/base/httpclient.h',
|
||||||
|
'source/talk/base/httpclient.cc',
|
||||||
|
'source/talk/base/httpcommon-inl.h',
|
||||||
|
'source/talk/base/httpcommon.cc',
|
||||||
|
'source/talk/base/httpcommon.h',
|
||||||
|
'source/talk/base/httprequest.cc',
|
||||||
|
'source/talk/base/httprequest.h',
|
||||||
|
'source/talk/base/json.cc',
|
||||||
|
'source/talk/base/json.h',
|
||||||
|
'source/talk/base/linked_ptr.h',
|
||||||
|
'source/talk/base/logging.cc',
|
||||||
|
'source/talk/base/md5.h',
|
||||||
|
'source/talk/base/md5c.c',
|
||||||
|
'source/talk/base/messagehandler.cc',
|
||||||
|
'source/talk/base/messagehandler.h',
|
||||||
|
'source/talk/base/messagequeue.cc',
|
||||||
|
'source/talk/base/messagequeue.h',
|
||||||
|
'source/talk/base/nethelpers.cc',
|
||||||
|
'source/talk/base/nethelpers.h',
|
||||||
|
'source/talk/base/network.cc',
|
||||||
|
'source/talk/base/network.h',
|
||||||
|
'source/talk/base/pathutils.cc',
|
||||||
|
'source/talk/base/pathutils.h',
|
||||||
|
'source/talk/base/physicalsocketserver.cc',
|
||||||
|
'source/talk/base/physicalsocketserver.h',
|
||||||
|
'source/talk/base/proxydetect.cc',
|
||||||
|
'source/talk/base/proxydetect.h',
|
||||||
|
'source/talk/base/proxyinfo.cc',
|
||||||
|
'source/talk/base/proxyinfo.h',
|
||||||
|
'source/talk/base/ratetracker.cc',
|
||||||
|
'source/talk/base/ratetracker.h',
|
||||||
|
'source/talk/base/sec_buffer.h',
|
||||||
|
'source/talk/base/signalthread.cc',
|
||||||
|
'source/talk/base/signalthread.h',
|
||||||
|
'source/talk/base/sigslot.h',
|
||||||
|
'source/talk/base/sigslotrepeater.h',
|
||||||
|
'source/talk/base/socket.h',
|
||||||
|
'source/talk/base/socketadapters.cc',
|
||||||
|
'source/talk/base/socketadapters.h',
|
||||||
|
'source/talk/base/socketaddress.cc',
|
||||||
|
'source/talk/base/socketaddress.h',
|
||||||
|
'source/talk/base/socketaddresspair.cc',
|
||||||
|
'source/talk/base/socketaddresspair.h',
|
||||||
|
'source/talk/base/socketfactory.h',
|
||||||
|
'source/talk/base/socketpool.cc',
|
||||||
|
'source/talk/base/socketpool.h',
|
||||||
|
'source/talk/base/socketserver.h',
|
||||||
|
'source/talk/base/socketstream.cc',
|
||||||
|
'source/talk/base/socketstream.h',
|
||||||
|
'source/talk/base/ssladapter.cc',
|
||||||
|
'source/talk/base/ssladapter.h',
|
||||||
|
'source/talk/base/sslsocketfactory.cc',
|
||||||
|
'source/talk/base/sslsocketfactory.h',
|
||||||
|
'source/talk/base/stream.cc',
|
||||||
|
'source/talk/base/stream.h',
|
||||||
|
'source/talk/base/stringdigest.cc',
|
||||||
|
'source/talk/base/stringdigest.h',
|
||||||
|
'source/talk/base/stringencode.cc',
|
||||||
|
'source/talk/base/stringencode.h',
|
||||||
|
'source/talk/base/stringutils.cc',
|
||||||
|
'source/talk/base/stringutils.h',
|
||||||
|
'source/talk/base/task.cc',
|
||||||
|
'source/talk/base/task.h',
|
||||||
|
'source/talk/base/taskparent.cc',
|
||||||
|
'source/talk/base/taskparent.h',
|
||||||
|
'source/talk/base/taskrunner.cc',
|
||||||
|
'source/talk/base/taskrunner.h',
|
||||||
|
'source/talk/base/thread.cc',
|
||||||
|
'source/talk/base/thread.h',
|
||||||
|
'source/talk/base/time.cc',
|
||||||
|
'source/talk/base/time.h',
|
||||||
|
'source/talk/base/urlencode.cc',
|
||||||
|
'source/talk/base/urlencode.h',
|
||||||
|
'source/talk/xmllite/xmlbuilder.cc',
|
||||||
|
'source/talk/xmllite/xmlbuilder.h',
|
||||||
|
'source/talk/xmllite/xmlconstants.cc',
|
||||||
|
'source/talk/xmllite/xmlconstants.h',
|
||||||
|
'source/talk/xmllite/xmlelement.cc',
|
||||||
|
'source/talk/xmllite/xmlelement.h',
|
||||||
|
'source/talk/xmllite/xmlnsstack.cc',
|
||||||
|
'source/talk/xmllite/xmlnsstack.h',
|
||||||
|
'source/talk/xmllite/xmlparser.cc',
|
||||||
|
'source/talk/xmllite/xmlparser.h',
|
||||||
|
'source/talk/xmllite/xmlprinter.cc',
|
||||||
|
'source/talk/xmllite/xmlprinter.h',
|
||||||
|
'source/talk/xmpp/asyncsocket.h',
|
||||||
|
'source/talk/xmpp/constants.cc',
|
||||||
|
'source/talk/xmpp/constants.h',
|
||||||
|
'source/talk/xmpp/jid.cc',
|
||||||
|
'source/talk/xmpp/jid.h',
|
||||||
|
'source/talk/xmpp/plainsaslhandler.h',
|
||||||
|
'source/talk/xmpp/prexmppauth.h',
|
||||||
|
'source/talk/xmpp/ratelimitmanager.cc',
|
||||||
|
'source/talk/xmpp/ratelimitmanager.h',
|
||||||
|
'source/talk/xmpp/saslcookiemechanism.h',
|
||||||
|
'source/talk/xmpp/saslhandler.h',
|
||||||
|
'source/talk/xmpp/saslmechanism.cc',
|
||||||
|
'source/talk/xmpp/saslmechanism.h',
|
||||||
|
'source/talk/xmpp/saslplainmechanism.h',
|
||||||
|
'source/talk/xmpp/xmppclient.cc',
|
||||||
|
'source/talk/xmpp/xmppclient.h',
|
||||||
|
'source/talk/xmpp/xmppclientsettings.h',
|
||||||
|
'source/talk/xmpp/xmppengine.h',
|
||||||
|
'source/talk/xmpp/xmppengineimpl.cc',
|
||||||
|
'source/talk/xmpp/xmppengineimpl.h',
|
||||||
|
'source/talk/xmpp/xmppengineimpl_iq.cc',
|
||||||
|
'source/talk/xmpp/xmpplogintask.cc',
|
||||||
|
'source/talk/xmpp/xmpplogintask.h',
|
||||||
|
'source/talk/xmpp/xmppstanzaparser.cc',
|
||||||
|
'source/talk/xmpp/xmppstanzaparser.h',
|
||||||
|
'source/talk/xmpp/xmpptask.cc',
|
||||||
|
'source/talk/xmpp/xmpptask.h',
|
||||||
|
],
|
||||||
|
'conditions': [
|
||||||
|
['OS=="win"', {
|
||||||
|
'sources': [
|
||||||
|
'<(overrides)/talk/base/win32socketinit.cc',
|
||||||
|
'source/talk/base/schanneladapter.cc',
|
||||||
|
'source/talk/base/schanneladapter.h',
|
||||||
|
'source/talk/base/win32.h',
|
||||||
|
'source/talk/base/win32.cc',
|
||||||
|
'source/talk/base/win32filesystem.cc',
|
||||||
|
'source/talk/base/win32filesystem.h',
|
||||||
|
'source/talk/base/win32window.h',
|
||||||
|
'source/talk/base/win32window.cc',
|
||||||
|
'source/talk/base/win32securityerrors.cc',
|
||||||
|
'source/talk/base/winfirewall.cc',
|
||||||
|
'source/talk/base/winfirewall.h',
|
||||||
|
'source/talk/base/winping.cc',
|
||||||
|
'source/talk/base/winping.h',
|
||||||
|
],
|
||||||
|
}],
|
||||||
|
['OS=="linux" or OS=="mac" or OS=="freebsd" or OS=="openbsd"', {
|
||||||
|
'sources': [
|
||||||
|
'source/talk/base/latebindingsymboltable.cc',
|
||||||
|
'source/talk/base/latebindingsymboltable.h',
|
||||||
|
'source/talk/base/sslstreamadapter.cc',
|
||||||
|
'source/talk/base/sslstreamadapter.h',
|
||||||
|
'source/talk/base/unixfilesystem.cc',
|
||||||
|
'source/talk/base/unixfilesystem.h',
|
||||||
|
],
|
||||||
|
}],
|
||||||
|
['OS=="linux"', {
|
||||||
|
'sources': [
|
||||||
|
'source/talk/base/linux.cc',
|
||||||
|
'source/talk/base/linux.h',
|
||||||
|
],
|
||||||
|
}],
|
||||||
|
['OS=="mac"', {
|
||||||
|
'sources': [
|
||||||
|
'source/talk/base/macconversion.cc',
|
||||||
|
'source/talk/base/macconversion.h',
|
||||||
|
'source/talk/base/macutils.cc',
|
||||||
|
'source/talk/base/macutils.h',
|
||||||
|
],
|
||||||
|
}],
|
||||||
|
['inside_chromium_build==1', {
|
||||||
|
'dependencies': [
|
||||||
|
'source/talk/third_party/jsoncpp/jsoncpp.gyp:jsoncpp',
|
||||||
|
],
|
||||||
|
}, {
|
||||||
|
'dependencies': [
|
||||||
|
'../../third_party/jsoncpp/jsoncpp.gyp:jsoncpp',
|
||||||
|
],
|
||||||
|
} ], # inside_chromium_build
|
||||||
|
],
|
||||||
|
},
|
||||||
|
# This has to be is a separate project due to a bug in MSVS:
|
||||||
|
# https://connect.microsoft.com/VisualStudio/feedback/details/368272/duplicate-cpp-filename-in-c-project-visual-studio-2008
|
||||||
|
# We have two files named "constants.cc" and MSVS doesn't handle this
|
||||||
|
# properly.
|
||||||
|
{
|
||||||
|
'target_name': 'libjingle_p2p',
|
||||||
|
'type': 'static_library',
|
||||||
|
'sources': [
|
||||||
|
'source/talk/p2p/base/candidate.h',
|
||||||
|
'source/talk/p2p/base/common.h',
|
||||||
|
'source/talk/p2p/base/constants.cc',
|
||||||
|
'source/talk/p2p/base/constants.h',
|
||||||
|
'source/talk/p2p/base/p2ptransport.cc',
|
||||||
|
'source/talk/p2p/base/p2ptransport.h',
|
||||||
|
'source/talk/p2p/base/p2ptransportchannel.cc',
|
||||||
|
'source/talk/p2p/base/p2ptransportchannel.h',
|
||||||
|
'source/talk/p2p/base/port.cc',
|
||||||
|
'source/talk/p2p/base/port.h',
|
||||||
|
'source/talk/p2p/base/portallocator.h',
|
||||||
|
'source/talk/p2p/base/pseudotcp.cc',
|
||||||
|
'source/talk/p2p/base/pseudotcp.h',
|
||||||
|
'source/talk/p2p/base/rawtransport.cc',
|
||||||
|
'source/talk/p2p/base/rawtransport.h',
|
||||||
|
'source/talk/p2p/base/rawtransportchannel.cc',
|
||||||
|
'source/talk/p2p/base/rawtransportchannel.h',
|
||||||
|
'source/talk/p2p/base/relayport.cc',
|
||||||
|
'source/talk/p2p/base/relayport.h',
|
||||||
|
'source/talk/p2p/base/session.cc',
|
||||||
|
'source/talk/p2p/base/session.h',
|
||||||
|
'source/talk/p2p/base/sessionclient.h',
|
||||||
|
'source/talk/p2p/base/sessiondescription.cc',
|
||||||
|
'source/talk/p2p/base/sessiondescription.h',
|
||||||
|
'source/talk/p2p/base/sessionid.h',
|
||||||
|
'source/talk/p2p/base/sessionmanager.cc',
|
||||||
|
'source/talk/p2p/base/sessionmanager.h',
|
||||||
|
'source/talk/p2p/base/sessionmessages.cc',
|
||||||
|
'source/talk/p2p/base/sessionmessages.h',
|
||||||
|
'source/talk/p2p/base/parsing.cc',
|
||||||
|
'source/talk/p2p/base/parsing.h',
|
||||||
|
'source/talk/p2p/base/stun.cc',
|
||||||
|
'source/talk/p2p/base/stun.h',
|
||||||
|
'source/talk/p2p/base/stunport.cc',
|
||||||
|
'source/talk/p2p/base/stunport.h',
|
||||||
|
'source/talk/p2p/base/stunrequest.cc',
|
||||||
|
'source/talk/p2p/base/stunrequest.h',
|
||||||
|
'source/talk/p2p/base/tcpport.cc',
|
||||||
|
'source/talk/p2p/base/tcpport.h',
|
||||||
|
'source/talk/p2p/base/transport.cc',
|
||||||
|
'source/talk/p2p/base/transport.h',
|
||||||
|
'source/talk/p2p/base/transportchannel.cc',
|
||||||
|
'source/talk/p2p/base/transportchannel.h',
|
||||||
|
'source/talk/p2p/base/transportchannelimpl.h',
|
||||||
|
'source/talk/p2p/base/transportchannelproxy.cc',
|
||||||
|
'source/talk/p2p/base/transportchannelproxy.h',
|
||||||
|
'source/talk/p2p/base/udpport.cc',
|
||||||
|
'source/talk/p2p/base/udpport.h',
|
||||||
|
'source/talk/p2p/client/basicportallocator.cc',
|
||||||
|
'source/talk/p2p/client/basicportallocator.h',
|
||||||
|
'source/talk/p2p/client/httpportallocator.cc',
|
||||||
|
'source/talk/p2p/client/httpportallocator.h',
|
||||||
|
'source/talk/p2p/client/sessionmanagertask.h',
|
||||||
|
'source/talk/p2p/client/sessionsendtask.h',
|
||||||
|
'source/talk/p2p/client/socketmonitor.cc',
|
||||||
|
'source/talk/p2p/client/socketmonitor.h',
|
||||||
|
'source/talk/session/phone/audiomonitor.cc',
|
||||||
|
'source/talk/session/phone/audiomonitor.h',
|
||||||
|
'source/talk/session/phone/call.cc',
|
||||||
|
'source/talk/session/phone/call.h',
|
||||||
|
'source/talk/session/phone/channel.cc',
|
||||||
|
'source/talk/session/phone/channel.h',
|
||||||
|
'source/talk/session/phone/channelmanager.cc',
|
||||||
|
'source/talk/session/phone/channelmanager.h',
|
||||||
|
'source/talk/session/phone/codec.cc',
|
||||||
|
'source/talk/session/phone/codec.h',
|
||||||
|
'source/talk/session/phone/cryptoparams.h',
|
||||||
|
'source/talk/session/phone/devicemanager.cc',
|
||||||
|
'source/talk/session/phone/devicemanager.h',
|
||||||
|
'source/talk/session/phone/filemediaengine.cc',
|
||||||
|
'source/talk/session/phone/filemediaengine.h',
|
||||||
|
'source/talk/session/phone/mediachannel.h',
|
||||||
|
'source/talk/session/phone/mediaengine.cc',
|
||||||
|
'source/talk/session/phone/mediaengine.h',
|
||||||
|
'source/talk/session/phone/mediamessages.cc',
|
||||||
|
'source/talk/session/phone/mediamessages.h',
|
||||||
|
'source/talk/session/phone/mediamonitor.cc',
|
||||||
|
'source/talk/session/phone/mediamonitor.h',
|
||||||
|
'source/talk/session/phone/mediasessionclient.cc',
|
||||||
|
'source/talk/session/phone/mediasessionclient.h',
|
||||||
|
'source/talk/session/phone/mediasink.h',
|
||||||
|
'source/talk/session/phone/rtcpmuxfilter.cc',
|
||||||
|
'source/talk/session/phone/rtcpmuxfilter.h',
|
||||||
|
'source/talk/session/phone/rtpdump.cc',
|
||||||
|
'source/talk/session/phone/rtpdump.h',
|
||||||
|
'source/talk/session/phone/rtputils.cc',
|
||||||
|
'source/talk/session/phone/rtputils.h',
|
||||||
|
'source/talk/session/phone/soundclip.cc',
|
||||||
|
'source/talk/session/phone/soundclip.h',
|
||||||
|
'source/talk/session/phone/srtpfilter.cc',
|
||||||
|
'source/talk/session/phone/srtpfilter.h',
|
||||||
|
'source/talk/session/phone/videocommon.h',
|
||||||
|
'source/talk/session/phone/voicechannel.h',
|
||||||
|
'source/talk/session/tunnel/pseudotcpchannel.cc',
|
||||||
|
'source/talk/session/tunnel/pseudotcpchannel.h',
|
||||||
|
'source/talk/session/tunnel/tunnelsessionclient.cc',
|
||||||
|
'source/talk/session/tunnel/tunnelsessionclient.h',
|
||||||
|
],
|
||||||
|
'conditions': [
|
||||||
|
['OS=="linux"', {
|
||||||
|
'sources': [
|
||||||
|
'source/talk/session/phone/libudevsymboltable.cc',
|
||||||
|
'source/talk/session/phone/libudevsymboltable.h',
|
||||||
|
'source/talk/session/phone/v4llookup.cc',
|
||||||
|
'source/talk/session/phone/v4llookup.h',
|
||||||
|
],
|
||||||
|
'include_dirs': [
|
||||||
|
'source/talk/third_party/libudev',
|
||||||
|
],
|
||||||
|
}],
|
||||||
|
['inside_chromium_build==1', {
|
||||||
|
'dependencies': [
|
||||||
|
'libjingle',
|
||||||
|
'../webrtc/video_engine/main/source/video_engine_core.gyp:video_engine_core',
|
||||||
|
'../webrtc/voice_engine/main/source/voice_engine_core.gyp:voice_engine_core',
|
||||||
|
],
|
||||||
|
'defines': [
|
||||||
|
'PLATFORM_CHROMIUM',
|
||||||
|
],
|
||||||
|
}, {
|
||||||
|
'dependencies': [
|
||||||
|
'libjingle',
|
||||||
|
'../../trunk/video_engine/main/source/video_engine_core.gyp:video_engine_core',
|
||||||
|
'../../trunk/voice_engine/main/source/voice_engine_core.gyp:voice_engine_core',
|
||||||
|
],
|
||||||
|
} ], # inside_chromium_build
|
||||||
|
], # conditions
|
||||||
|
},
|
||||||
|
# seperate project for app
|
||||||
|
{
|
||||||
|
'target_name': 'libjingle_app',
|
||||||
|
'type': '<(library)',
|
||||||
|
'sources': [
|
||||||
|
'source/talk/app/peerconnection.cc',
|
||||||
|
'source/talk/app/peerconnection.h',
|
||||||
|
'source/talk/app/videoengine.h',
|
||||||
|
'source/talk/app/videomediaengine.cc',
|
||||||
|
'source/talk/app/videomediaengine.h',
|
||||||
|
'source/talk/app/voiceengine.h',
|
||||||
|
'source/talk/app/voicemediaengine.cc',
|
||||||
|
'source/talk/app/voicemediaengine.h',
|
||||||
|
'source/talk/app/webrtc_json.cc',
|
||||||
|
'source/talk/app/webrtc_json.h',
|
||||||
|
'source/talk/app/webrtcchannelmanager.cc',
|
||||||
|
'source/talk/app/webrtcchannelmanager.h',
|
||||||
|
'source/talk/app/webrtcsession.cc',
|
||||||
|
'source/talk/app/webrtcsession.h',
|
||||||
|
'source/talk/app/webrtcsessionimpl.cc',
|
||||||
|
'source/talk/app/webrtcsessionimpl.h',
|
||||||
|
'source/talk/app/pc_transport_impl.cc',
|
||||||
|
'source/talk/app/pc_transport_impl.h',
|
||||||
|
],
|
||||||
|
'direct_dependent_settings': {
|
||||||
|
'conditions': [
|
||||||
|
['inside_chromium_build==1', {
|
||||||
|
'defines': [
|
||||||
|
'PLATFORM_CHROMIUM',
|
||||||
|
],
|
||||||
|
},{
|
||||||
|
'sources': [
|
||||||
|
'source/talk/app/p2p_transport_manager.cc',
|
||||||
|
'source/talk/app/p2p_transport_manager.h',
|
||||||
|
],
|
||||||
|
}],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
'dependencies': [
|
||||||
|
],
|
||||||
|
'conditions': [
|
||||||
|
['inside_chromium_build==1', {
|
||||||
|
'dependencies': [
|
||||||
|
'../webrtc/modules/video_capture/main/source/video_capture.gyp:video_capture_module',
|
||||||
|
'../webrtc/video_engine/main/source/video_engine_core.gyp:video_engine_core',
|
||||||
|
'../webrtc/voice_engine/main/source/voice_engine_core.gyp:voice_engine_core',
|
||||||
|
'../webrtc/system_wrappers/source/system_wrappers.gyp:system_wrappers',
|
||||||
|
'libjingle_p2p',
|
||||||
|
'source/talk/third_party/jsoncpp/jsoncpp.gyp:jsoncpp',
|
||||||
|
],
|
||||||
|
'defines': [
|
||||||
|
'PLATFORM_CHROMIUM',
|
||||||
|
],
|
||||||
|
}, {
|
||||||
|
'dependencies': [
|
||||||
|
'../../third_party/jsoncpp/jsoncpp.gyp:jsoncpp',
|
||||||
|
'../../trunk/modules/video_capture/main/source/video_capture.gyp:video_capture_module',
|
||||||
|
'../../trunk/video_engine/main/source/video_engine_core.gyp:video_engine_core',
|
||||||
|
'../../trunk/voice_engine/main/source/voice_engine_core.gyp:voice_engine_core',
|
||||||
|
'../../trunk/system_wrappers/source/system_wrappers.gyp:system_wrappers',
|
||||||
|
'libjingle_p2p',
|
||||||
|
],
|
||||||
|
} ], # inside_chromium_build
|
||||||
|
], # conditions
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
'target_name': 'session_test_app',
|
||||||
|
'conditions': [
|
||||||
|
['OS=="win"', {
|
||||||
|
'type': 'executable',
|
||||||
|
'sources': [
|
||||||
|
'source/talk/app/session_test/main_wnd.cc',
|
||||||
|
'source/talk/app/session_test/main_wnd.h',
|
||||||
|
'source/talk/app/session_test/session_test_main.cc',
|
||||||
|
],
|
||||||
|
'msvs_settings': {
|
||||||
|
'VCLinkerTool': {
|
||||||
|
'SubSystem': '2', # Windows
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
'type': 'none',
|
||||||
|
}],
|
||||||
|
['inside_chromium_build==1', {
|
||||||
|
'dependencies': [
|
||||||
|
'../webrtc/modules/video_capture/main/source/video_capture.gyp:video_capture_module',
|
||||||
|
'../webrtc/video_engine/main/source/video_engine_core.gyp:video_engine_core',
|
||||||
|
'../webrtc/voice_engine/main/source/voice_engine_core.gyp:voice_engine_core',
|
||||||
|
'../webrtc/system_wrappers/source/system_wrappers.gyp:system_wrappers',
|
||||||
|
'libjingle_app',
|
||||||
|
'libjingle_p2p',
|
||||||
|
'source/talk/third_party/jsoncpp/jsoncpp.gyp:jsoncpp',
|
||||||
|
],
|
||||||
|
}, {
|
||||||
|
'dependencies': [
|
||||||
|
'../../third_party/jsoncpp/jsoncpp.gyp:jsoncpp',
|
||||||
|
'../../trunk/modules/video_capture/main/source/video_capture.gyp:video_capture_module',
|
||||||
|
'../../trunk/voice_engine/main/source/voice_engine_core.gyp:voice_engine_core',
|
||||||
|
'../../trunk/system_wrappers/source/system_wrappers.gyp:system_wrappers',
|
||||||
|
'libjingle_app',
|
||||||
|
],
|
||||||
|
} ], # inside_chromium_build
|
||||||
|
], # conditions
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
# Local Variables:
|
||||||
|
# tab-width:2
|
||||||
|
# indent-tabs-mode:nil
|
||||||
|
# End:
|
||||||
|
# vim: set expandtab tabstop=2 shiftwidth=2:
|
||||||
BIN
third_party_mods/libjingle/source/talk/app/ClassDiagram2.png
Normal file
BIN
third_party_mods/libjingle/source/talk/app/ClassDiagram2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 13 KiB |
@ -0,0 +1,75 @@
|
|||||||
|
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
#include "talk/app/p2p_transport_manager.h"
|
||||||
|
|
||||||
|
#include "talk/base/socketaddress.h"
|
||||||
|
#include "talk/p2p/base/p2ptransportchannel.h"
|
||||||
|
#include "talk/p2p/client/httpportallocator.h"
|
||||||
|
#include "talk/p2p/client/basicportallocator.h"
|
||||||
|
|
||||||
|
namespace webrtc {
|
||||||
|
|
||||||
|
P2PTransportManager::P2PTransportManager(cricket::PortAllocator* allocator)
|
||||||
|
: event_handler_(NULL)
|
||||||
|
,state_(STATE_NONE)
|
||||||
|
,allocator_(allocator) {
|
||||||
|
}
|
||||||
|
|
||||||
|
P2PTransportManager::~P2PTransportManager() {
|
||||||
|
}
|
||||||
|
|
||||||
|
bool P2PTransportManager::Init(const std::string& name,
|
||||||
|
Protocol protocol,
|
||||||
|
const std::string& config,
|
||||||
|
EventHandler* event_handler) {
|
||||||
|
name_ = name;
|
||||||
|
event_handler_ = event_handler;
|
||||||
|
|
||||||
|
channel_.reset(new cricket::P2PTransportChannel(
|
||||||
|
name, "", NULL, allocator_));
|
||||||
|
channel_->SignalRequestSignaling.connect(
|
||||||
|
this, &P2PTransportManager::OnRequestSignaling);
|
||||||
|
channel_->SignalWritableState.connect(
|
||||||
|
this, &P2PTransportManager::OnReadableState);
|
||||||
|
channel_->SignalWritableState.connect(
|
||||||
|
this, &P2PTransportManager::OnWriteableState);
|
||||||
|
channel_->SignalCandidateReady.connect(
|
||||||
|
this, &P2PTransportManager::OnCandidateReady);
|
||||||
|
|
||||||
|
channel_->Connect();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool P2PTransportManager::AddRemoteCandidate(
|
||||||
|
const cricket::Candidate& candidate) {
|
||||||
|
channel_->OnCandidate(candidate);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
cricket::P2PTransportChannel* P2PTransportManager::GetP2PChannel() {
|
||||||
|
return channel_.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
void P2PTransportManager::OnRequestSignaling() {
|
||||||
|
channel_->OnSignalingReady();
|
||||||
|
}
|
||||||
|
|
||||||
|
void P2PTransportManager::OnCandidateReady(
|
||||||
|
cricket::TransportChannelImpl* channel,
|
||||||
|
const cricket::Candidate& candidate) {
|
||||||
|
event_handler_->OnCandidateReady(candidate);
|
||||||
|
}
|
||||||
|
|
||||||
|
void P2PTransportManager::OnReadableState(cricket::TransportChannel* channel) {
|
||||||
|
state_ = static_cast<State>(state_ | STATE_READABLE);
|
||||||
|
event_handler_->OnStateChange(state_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void P2PTransportManager::OnWriteableState(cricket::TransportChannel* channel) {
|
||||||
|
state_ = static_cast<State>(state_ | STATE_WRITABLE);
|
||||||
|
event_handler_->OnStateChange(state_);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,87 @@
|
|||||||
|
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
#ifndef TALK_APP_WEBRTC_P2P_TRANSPORT_MANAGER_H_
|
||||||
|
#define TALK_APP_WEBRTC_P2P_TRANSPORT_MANAGER_H_
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "talk/base/scoped_ptr.h"
|
||||||
|
#include "talk/base/sigslot.h"
|
||||||
|
|
||||||
|
namespace cricket {
|
||||||
|
class Candidate;
|
||||||
|
class P2PTransportChannel;
|
||||||
|
class PortAllocator;
|
||||||
|
class TransportChannel;
|
||||||
|
class TransportChannelImpl;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace talk_base {
|
||||||
|
class NetworkManager;
|
||||||
|
class PacketSocketFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace webrtc {
|
||||||
|
class P2PTransportManager : public sigslot::has_slots<>{
|
||||||
|
public:
|
||||||
|
enum State {
|
||||||
|
STATE_NONE = 0,
|
||||||
|
STATE_WRITABLE = 1,
|
||||||
|
STATE_READABLE = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Protocol {
|
||||||
|
PROTOCOL_UDP = 0,
|
||||||
|
PROTOCOL_TCP = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
class EventHandler {
|
||||||
|
public:
|
||||||
|
virtual ~EventHandler() {}
|
||||||
|
|
||||||
|
// Called for each local candidate.
|
||||||
|
virtual void OnCandidateReady(const cricket::Candidate& candidate) = 0;
|
||||||
|
|
||||||
|
// Called when readable of writable state of the stream changes.
|
||||||
|
virtual void OnStateChange(State state) = 0;
|
||||||
|
|
||||||
|
// Called when an error occures (e.g. TCP handshake
|
||||||
|
// failed). P2PTransportManager object is not usable after that and
|
||||||
|
// should be destroyed.
|
||||||
|
virtual void OnError(int error) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Create P2PTransportManager using specified NetworkManager and
|
||||||
|
// PacketSocketFactory. Takes ownership of |network_manager| and
|
||||||
|
// |socket_factory|.
|
||||||
|
P2PTransportManager(cricket::PortAllocator* allocator);
|
||||||
|
~P2PTransportManager();
|
||||||
|
|
||||||
|
bool Init(const std::string& name,
|
||||||
|
Protocol protocol,
|
||||||
|
const std::string& config,
|
||||||
|
EventHandler* event_handler);
|
||||||
|
bool AddRemoteCandidate(const cricket::Candidate& address);
|
||||||
|
cricket::P2PTransportChannel* GetP2PChannel();
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
void OnRequestSignaling();
|
||||||
|
void OnCandidateReady(cricket::TransportChannelImpl* channel,
|
||||||
|
const cricket::Candidate& candidate);
|
||||||
|
void OnReadableState(cricket::TransportChannel* channel);
|
||||||
|
void OnWriteableState(cricket::TransportChannel* channel);
|
||||||
|
|
||||||
|
std::string name_;
|
||||||
|
EventHandler* event_handler_;
|
||||||
|
State state_;
|
||||||
|
|
||||||
|
cricket::PortAllocator* allocator_;
|
||||||
|
talk_base::scoped_ptr<cricket::P2PTransportChannel> channel_;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif // TALK_APP_WEBRTC_P2P_TRANSPORT_MANAGER_H_
|
||||||
359
third_party_mods/libjingle/source/talk/app/pc_transport_impl.cc
Normal file
359
third_party_mods/libjingle/source/talk/app/pc_transport_impl.cc
Normal file
@ -0,0 +1,359 @@
|
|||||||
|
/*
|
||||||
|
* pc_transport_impl.cc
|
||||||
|
*
|
||||||
|
* Created on: May 2, 2011
|
||||||
|
* Author: mallinath
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "talk/app/pc_transport_impl.h"
|
||||||
|
|
||||||
|
#ifdef PLATFORM_CHROMIUM
|
||||||
|
#include "base/values.h"
|
||||||
|
#include "content/common/json_value_serializer.h"
|
||||||
|
#include "content/renderer/p2p/p2p_transport_impl.h"
|
||||||
|
#include "jingle/glue/thread_wrapper.h"
|
||||||
|
#include "net/base/io_buffer.h"
|
||||||
|
#include "net/socket/socket.h"
|
||||||
|
#else
|
||||||
|
#include "talk/app/p2p_transport_manager.h"
|
||||||
|
#endif
|
||||||
|
#include "talk/p2p/base/transportchannel.h"
|
||||||
|
#include "talk/app/webrtcsessionimpl.h"
|
||||||
|
#include "talk/app/peerconnection.h"
|
||||||
|
|
||||||
|
namespace webrtc {
|
||||||
|
enum {
|
||||||
|
MSG_RTC_ONREADPACKET = 1,
|
||||||
|
MSG_RTC_TRANSPORTINIT,
|
||||||
|
MSG_RTC_ADDREMOTECANDIDATE,
|
||||||
|
MSG_RTC_ONCANDIDATEREADY,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MediaDataMsgParams : public talk_base::MessageData {
|
||||||
|
MediaDataMsgParams(cricket::TransportChannel* channel,
|
||||||
|
const char* dataPtr,
|
||||||
|
int len)
|
||||||
|
: channel(channel), data(dataPtr), len(len) {}
|
||||||
|
|
||||||
|
cricket::TransportChannel* channel;
|
||||||
|
const char* data;
|
||||||
|
int len;
|
||||||
|
};
|
||||||
|
|
||||||
|
PC_Transport_Impl::PC_Transport_Impl (WebRTCSessionImpl* session)
|
||||||
|
: session_(session),
|
||||||
|
#ifdef PLATFORM_CHROMIUM
|
||||||
|
ALLOW_THIS_IN_INITIALIZER_LIST(
|
||||||
|
channel_read_callback_(this, &PC_Transport_Impl::OnRead)),
|
||||||
|
ALLOW_THIS_IN_INITIALIZER_LIST(
|
||||||
|
channel_write_callback_(this, &PC_Transport_Impl::OnWrite)),
|
||||||
|
#endif
|
||||||
|
writable_(false),
|
||||||
|
event_(false, false),
|
||||||
|
network_thread_jingle_(session_->connection()->media_thread())
|
||||||
|
{
|
||||||
|
#ifdef PLATFORM_CHROMIUM
|
||||||
|
// Before proceeding, ensure we have libjingle thread wrapper for
|
||||||
|
// the current thread.
|
||||||
|
jingle_glue::JingleThreadWrapper::EnsureForCurrentThread();
|
||||||
|
network_thread_chromium_ = talk_base::Thread::Current();
|
||||||
|
#endif
|
||||||
|
event_.Set();
|
||||||
|
}
|
||||||
|
|
||||||
|
PC_Transport_Impl::~PC_Transport_Impl() {
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PC_Transport_Impl::Init(const std::string& name) {
|
||||||
|
#ifdef PLATFORM_CHROMIUM
|
||||||
|
if(network_thread_chromium_ != talk_base::Thread::Current()) {
|
||||||
|
network_thread_chromium_->Post(this, MSG_RTC_TRANSPORTINIT,
|
||||||
|
new talk_base::TypedMessageData<std::string> (name));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if(network_thread_jingle_ != talk_base::Thread::Current()) {
|
||||||
|
network_thread_jingle_->Send(this, MSG_RTC_TRANSPORTINIT,
|
||||||
|
new talk_base::TypedMessageData<std::string> (name));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
name_ = name;
|
||||||
|
p2p_transport_.reset(CreateP2PTransport());
|
||||||
|
|
||||||
|
#ifdef PLATFORM_CHROMIUM
|
||||||
|
webkit_glue::P2PTransport::Protocol protocol =
|
||||||
|
webkit_glue::P2PTransport::PROTOCOL_UDP;
|
||||||
|
#else
|
||||||
|
webrtc::P2PTransportManager::Protocol protocol =
|
||||||
|
webrtc::P2PTransportManager::PROTOCOL_UDP;
|
||||||
|
#endif
|
||||||
|
p2p_transport_->Init(name_, protocol, "", this);
|
||||||
|
|
||||||
|
#ifdef PLATFORM_CHROMIUM
|
||||||
|
StreamRead();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef PLATFORM_CHROMIUM
|
||||||
|
|
||||||
|
void PC_Transport_Impl::OnCandidateReady(const std::string& address) {
|
||||||
|
if(network_thread_chromium_ != talk_base::Thread::Current()) {
|
||||||
|
network_thread_chromium_->Post(this, MSG_RTC_ONCANDIDATEREADY,
|
||||||
|
new talk_base::TypedMessageData<std::string> (
|
||||||
|
address));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// using only first candidate
|
||||||
|
// use p2p_transport_impl.cc Deserialize method
|
||||||
|
cricket::Candidate candidate;
|
||||||
|
if (local_candidates_.empty()) {
|
||||||
|
cricket::Candidate candidate;
|
||||||
|
DeserializeCandidate(address, &candidate);
|
||||||
|
local_candidates_.push_back(candidate);
|
||||||
|
session_->OnCandidateReady(candidate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PC_Transport_Impl::AddRemoteCandidate(
|
||||||
|
const cricket::Candidate& candidate) {
|
||||||
|
if(network_thread_chromium_ != talk_base::Thread::Current()) {
|
||||||
|
network_thread_chromium_->Post(this, MSG_RTC_ADDREMOTECANDIDATE,
|
||||||
|
new talk_base::TypedMessageData<const cricket::Candidate*> (
|
||||||
|
&candidate));
|
||||||
|
// TODO: save the result
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!p2p_transport_.get())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return p2p_transport_->AddRemoteCandidate(SerializeCandidate(candidate));
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
void PC_Transport_Impl::OnCandidateReady(const cricket::Candidate& candidate) {
|
||||||
|
if(network_thread_jingle_ != talk_base::Thread::Current()) {
|
||||||
|
network_thread_jingle_->Send(this, MSG_RTC_ONCANDIDATEREADY,
|
||||||
|
new talk_base::TypedMessageData<const cricket::Candidate*> (
|
||||||
|
&candidate));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (local_candidates_.empty()) {
|
||||||
|
local_candidates_.push_back(candidate);
|
||||||
|
session_->OnCandidateReady(candidate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PC_Transport_Impl::AddRemoteCandidate(
|
||||||
|
const cricket::Candidate& candidate) {
|
||||||
|
if(network_thread_jingle_ != talk_base::Thread::Current()) {
|
||||||
|
network_thread_jingle_->Send(this, MSG_RTC_ADDREMOTECANDIDATE,
|
||||||
|
new talk_base::TypedMessageData<const cricket::Candidate*> (
|
||||||
|
&candidate));
|
||||||
|
// TODO: save the result
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!p2p_transport_.get())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return p2p_transport_->AddRemoteCandidate(candidate);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef PLATFORM_CHROMIUM
|
||||||
|
|
||||||
|
int32 PC_Transport_Impl::DoRecv() {
|
||||||
|
if (!p2p_transport_.get())
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
net::Socket* channel = p2p_transport_->GetChannel();
|
||||||
|
if (!channel)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
scoped_refptr<net::IOBuffer> buffer =
|
||||||
|
new net::WrappedIOBuffer(static_cast<const char*>(recv_buffer_));
|
||||||
|
int result = channel->Read(
|
||||||
|
buffer, kMaxRtpRtcpPacketLen, &channel_read_callback_);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PC_Transport_Impl::OnRead(int result) {
|
||||||
|
network_thread_jingle_->Post(
|
||||||
|
this, MSG_RTC_ONREADPACKET, new MediaDataMsgParams(
|
||||||
|
GetP2PChannel(), recv_buffer_, result));
|
||||||
|
StreamRead();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PC_Transport_Impl::OnWrite(int result) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
net::Socket* PC_Transport_Impl::GetChannel() {
|
||||||
|
if (!p2p_transport_.get())
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return p2p_transport_->GetChannel();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PC_Transport_Impl::StreamRead() {
|
||||||
|
event_.Wait(talk_base::kForever);
|
||||||
|
DoRecv();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PC_Transport_Impl::OnReadPacket_w(cricket::TransportChannel* channel,
|
||||||
|
const char* data,
|
||||||
|
size_t len) {
|
||||||
|
session()->SignalReadPacket(channel, data, len);
|
||||||
|
event_.Set();
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string PC_Transport_Impl::SerializeCandidate(
|
||||||
|
const cricket::Candidate& candidate) {
|
||||||
|
// TODO(sergeyu): Use SDP to format candidates?
|
||||||
|
DictionaryValue value;
|
||||||
|
value.SetString("name", candidate.name());
|
||||||
|
value.SetString("ip", candidate.address().IPAsString());
|
||||||
|
value.SetInteger("port", candidate.address().port());
|
||||||
|
value.SetString("type", candidate.type());
|
||||||
|
value.SetString("protocol", candidate.protocol());
|
||||||
|
value.SetString("username", candidate.username());
|
||||||
|
value.SetString("password", candidate.password());
|
||||||
|
value.SetDouble("preference", candidate.preference());
|
||||||
|
value.SetInteger("generation", candidate.generation());
|
||||||
|
|
||||||
|
std::string result;
|
||||||
|
JSONStringValueSerializer serializer(&result);
|
||||||
|
serializer.Serialize(value);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PC_Transport_Impl::DeserializeCandidate(const std::string& address,
|
||||||
|
cricket::Candidate* candidate) {
|
||||||
|
JSONStringValueSerializer deserializer(address);
|
||||||
|
scoped_ptr<Value> value(deserializer.Deserialize(NULL, NULL));
|
||||||
|
if (!value.get() || !value->IsType(Value::TYPE_DICTIONARY)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
DictionaryValue* dic_value = static_cast<DictionaryValue*>(value.get());
|
||||||
|
|
||||||
|
std::string name;
|
||||||
|
std::string ip;
|
||||||
|
int port;
|
||||||
|
std::string type;
|
||||||
|
std::string protocol;
|
||||||
|
std::string username;
|
||||||
|
std::string password;
|
||||||
|
double preference;
|
||||||
|
int generation;
|
||||||
|
|
||||||
|
if (!dic_value->GetString("name", &name) ||
|
||||||
|
!dic_value->GetString("ip", &ip) ||
|
||||||
|
!dic_value->GetInteger("port", &port) ||
|
||||||
|
!dic_value->GetString("type", &type) ||
|
||||||
|
!dic_value->GetString("protocol", &protocol) ||
|
||||||
|
!dic_value->GetString("username", &username) ||
|
||||||
|
!dic_value->GetString("password", &password) ||
|
||||||
|
!dic_value->GetDouble("preference", &preference) ||
|
||||||
|
!dic_value->GetInteger("generation", &generation)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
candidate->set_name(name);
|
||||||
|
candidate->set_address(talk_base::SocketAddress(ip, port));
|
||||||
|
candidate->set_type(type);
|
||||||
|
candidate->set_protocol(protocol);
|
||||||
|
candidate->set_username(username);
|
||||||
|
candidate->set_password(password);
|
||||||
|
candidate->set_preference(static_cast<float>(preference));
|
||||||
|
candidate->set_generation(generation);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void PC_Transport_Impl::OnStateChange(P2PTransportClass::State state) {
|
||||||
|
writable_ = (state | P2PTransportClass::STATE_WRITABLE) != 0;
|
||||||
|
if (writable_) {
|
||||||
|
session_->OnStateChange(state, p2p_transport()->GetP2PChannel());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PC_Transport_Impl::OnError(int error) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
cricket::TransportChannel* PC_Transport_Impl::GetP2PChannel() {
|
||||||
|
if (!p2p_transport_.get())
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return p2p_transport_->GetP2PChannel();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PC_Transport_Impl::OnMessage(talk_base::Message* message) {
|
||||||
|
talk_base::MessageData* data = message->pdata;
|
||||||
|
switch(message->message_id) {
|
||||||
|
case MSG_RTC_TRANSPORTINIT : {
|
||||||
|
talk_base::TypedMessageData<std::string> *p =
|
||||||
|
static_cast<talk_base::TypedMessageData<std::string>* >(data);
|
||||||
|
Init(p->data());
|
||||||
|
delete p;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MSG_RTC_ADDREMOTECANDIDATE : {
|
||||||
|
talk_base::TypedMessageData<const cricket::Candidate*> *p =
|
||||||
|
static_cast<talk_base::TypedMessageData<const cricket::Candidate*>* >(data);
|
||||||
|
AddRemoteCandidate(*p->data());
|
||||||
|
delete p;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#ifdef PLATFORM_CHROMIUM
|
||||||
|
case MSG_RTC_ONCANDIDATEREADY : {
|
||||||
|
talk_base::TypedMessageData<std::string> *p =
|
||||||
|
static_cast<talk_base::TypedMessageData<std::string>* >(data);
|
||||||
|
OnCandidateReady(p->data());
|
||||||
|
delete p;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MSG_RTC_ONREADPACKET : {
|
||||||
|
MediaDataMsgParams* p = static_cast<MediaDataMsgParams*> (data);
|
||||||
|
ASSERT (p != NULL);
|
||||||
|
OnReadPacket_w(p->channel, p->data, p->len);
|
||||||
|
delete data;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
case MSG_RTC_ONCANDIDATEREADY : {
|
||||||
|
talk_base::TypedMessageData<const cricket::Candidate*> *p =
|
||||||
|
static_cast<talk_base::TypedMessageData<const cricket::Candidate*>* >(data);
|
||||||
|
OnCandidateReady(*p->data());
|
||||||
|
delete p;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
ASSERT(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
P2PTransportClass* PC_Transport_Impl::CreateP2PTransport() {
|
||||||
|
#ifdef PLATFORM_CHROMIUM
|
||||||
|
return new P2PTransportImpl(
|
||||||
|
session()->connection()->p2p_socket_dispatcher());
|
||||||
|
#else
|
||||||
|
return new P2PTransportManager(session()->port_allocator());
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
} //namespace webrtc
|
||||||
|
|
||||||
109
third_party_mods/libjingle/source/talk/app/pc_transport_impl.h
Normal file
109
third_party_mods/libjingle/source/talk/app/pc_transport_impl.h
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
/*
|
||||||
|
* peerconnection_transport_impl.h
|
||||||
|
*
|
||||||
|
* Created on: May 2, 2011
|
||||||
|
* Author: mallinath
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TALK_APP_PEERCONNECTION_TRANSPORT_IMPL_H_
|
||||||
|
#define TALK_APP_PEERCONNECTION_TRANSPORT_IMPL_H_
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "talk/base/thread.h"
|
||||||
|
#include "talk/base/event.h"
|
||||||
|
#include "talk/base/messagehandler.h"
|
||||||
|
#include "talk/base/scoped_ptr.h"
|
||||||
|
|
||||||
|
#ifdef PLATFORM_CHROMIUM
|
||||||
|
#include "net/base/completion_callback.h"
|
||||||
|
#include "webkit/glue/p2p_transport.h"
|
||||||
|
class P2PTransportImpl;
|
||||||
|
#else
|
||||||
|
#include "talk/app/p2p_transport_manager.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef PLATFORM_CHROMIUM
|
||||||
|
typedef P2PTransportImpl TransportImplClass;
|
||||||
|
typedef webkit_glue::P2PTransport::EventHandler TransportEventHandler;
|
||||||
|
typedef webkit_glue::P2PTransport P2PTransportClass;
|
||||||
|
#else
|
||||||
|
typedef webrtc::P2PTransportManager TransportImplClass;
|
||||||
|
typedef webrtc::P2PTransportManager::EventHandler TransportEventHandler;
|
||||||
|
typedef webrtc::P2PTransportManager P2PTransportClass;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace cricket {
|
||||||
|
class TransportChannel;
|
||||||
|
class Candidate;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace webrtc {
|
||||||
|
|
||||||
|
const int kMaxRtpRtcpPacketLen = 1500;
|
||||||
|
|
||||||
|
class WebRTCSessionImpl;
|
||||||
|
// PC - PeerConnection
|
||||||
|
class PC_Transport_Impl : public talk_base::MessageHandler,
|
||||||
|
public TransportEventHandler {
|
||||||
|
public:
|
||||||
|
PC_Transport_Impl(WebRTCSessionImpl* session);
|
||||||
|
virtual ~PC_Transport_Impl();
|
||||||
|
|
||||||
|
bool Init(const std::string& name);
|
||||||
|
#ifdef PLATFORM_CHROMIUM
|
||||||
|
virtual void OnCandidateReady(const std::string& address);
|
||||||
|
#else
|
||||||
|
virtual void OnCandidateReady(const cricket::Candidate& candidate);
|
||||||
|
#endif
|
||||||
|
virtual void OnStateChange(P2PTransportClass::State state);
|
||||||
|
virtual void OnError(int error);
|
||||||
|
|
||||||
|
#ifdef PLATFORM_CHROMIUM
|
||||||
|
void OnRead(int result);
|
||||||
|
void OnWrite(int result);
|
||||||
|
net::Socket* GetChannel();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void OnMessage(talk_base::Message* message);
|
||||||
|
cricket::TransportChannel* GetP2PChannel();
|
||||||
|
bool AddRemoteCandidate(const cricket::Candidate& candidate);
|
||||||
|
WebRTCSessionImpl* session() { return session_; }
|
||||||
|
P2PTransportClass* p2p_transport() { return p2p_transport_.get(); }
|
||||||
|
const std::string& name() { return name_; }
|
||||||
|
std::vector<cricket::Candidate>& local_candidates() {
|
||||||
|
return local_candidates_;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void MsgSend(uint32 id);
|
||||||
|
P2PTransportClass* CreateP2PTransport();
|
||||||
|
#ifdef PLATFORM_CHROMIUM
|
||||||
|
void OnReadPacket_w(
|
||||||
|
cricket::TransportChannel* channel, const char* data, size_t len);
|
||||||
|
int32 DoRecv();
|
||||||
|
void StreamRead();
|
||||||
|
std::string SerializeCandidate(const cricket::Candidate& candidate);
|
||||||
|
bool DeserializeCandidate(const std::string& address,
|
||||||
|
cricket::Candidate* candidate);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
std::string name_;
|
||||||
|
WebRTCSessionImpl* session_;
|
||||||
|
talk_base::scoped_ptr<P2PTransportClass> p2p_transport_;
|
||||||
|
std::vector<cricket::Candidate> local_candidates_;
|
||||||
|
|
||||||
|
#ifdef PLATFORM_CHROMIUM
|
||||||
|
net::CompletionCallbackImpl<PC_Transport_Impl> channel_read_callback_;
|
||||||
|
net::CompletionCallbackImpl<PC_Transport_Impl> channel_write_callback_;
|
||||||
|
talk_base::Thread* network_thread_chromium_;
|
||||||
|
#endif
|
||||||
|
bool writable_;
|
||||||
|
char recv_buffer_[kMaxRtpRtcpPacketLen];
|
||||||
|
talk_base::Event event_;
|
||||||
|
talk_base::Thread* network_thread_jingle_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace webrtc
|
||||||
|
|
||||||
|
#endif /* TALK_APP_PEERCONNECTION_TRANSPORT_IMPL_H_ */
|
||||||
302
third_party_mods/libjingle/source/talk/app/peerconnection.cc
Normal file
302
third_party_mods/libjingle/source/talk/app/peerconnection.cc
Normal file
@ -0,0 +1,302 @@
|
|||||||
|
// Copyright 2011 Google Inc. All Rights Reserved.
|
||||||
|
// Author: mallinath@google.com (Mallinath Bareddy)
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "talk/app/peerconnection.h"
|
||||||
|
|
||||||
|
#include "talk/base/basicpacketsocketfactory.h"
|
||||||
|
#include "talk/base/helpers.h"
|
||||||
|
#include "talk/base/stringencode.h"
|
||||||
|
#include "talk/base/logging.h"
|
||||||
|
|
||||||
|
#include "talk/p2p/client/basicportallocator.h"
|
||||||
|
#include "talk/session/phone/mediasessionclient.h"
|
||||||
|
#include "talk/app/webrtcsessionimpl.h"
|
||||||
|
#include "talk/app/webrtc_json.h"
|
||||||
|
|
||||||
|
namespace webrtc {
|
||||||
|
|
||||||
|
static const size_t kConfigTokens = 2;
|
||||||
|
static const int kDefaultStunPort = 3478;
|
||||||
|
|
||||||
|
#ifdef PLATFORM_CHROMIUM
|
||||||
|
PeerConnection::PeerConnection(const std::string& config,
|
||||||
|
P2PSocketDispatcher* p2p_socket_dispatcher)
|
||||||
|
#else
|
||||||
|
PeerConnection::PeerConnection(const std::string& config)
|
||||||
|
#endif // PLATFORM_CHROMIUM
|
||||||
|
: config_(config)
|
||||||
|
,media_thread_(new talk_base::Thread)
|
||||||
|
,network_manager_(new talk_base::NetworkManager)
|
||||||
|
,signaling_thread_(new talk_base::Thread)
|
||||||
|
,initialized_(false)
|
||||||
|
,service_type_(SERVICE_COUNT)
|
||||||
|
,event_callback_(NULL)
|
||||||
|
,session_(NULL)
|
||||||
|
,incoming_(false)
|
||||||
|
#ifdef PLATFORM_CHROMIUM
|
||||||
|
,p2p_socket_dispatcher_(p2p_socket_dispatcher)
|
||||||
|
#endif // PLATFORM_CHROMIUM
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
PeerConnection::~PeerConnection() {
|
||||||
|
if (session_ != NULL) {
|
||||||
|
// Before deleting the session, make sure that the signaling thread isn't
|
||||||
|
// running (or wait for it if it is).
|
||||||
|
signaling_thread_.reset();
|
||||||
|
|
||||||
|
ASSERT(!session_->HasAudioStream());
|
||||||
|
ASSERT(!session_->HasVideoStream());
|
||||||
|
// TODO: the RemoveAllStreams has to be asynchronous. At the same
|
||||||
|
//time "delete session_" should be called after RemoveAllStreams completed.
|
||||||
|
delete session_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PeerConnection::Init() {
|
||||||
|
ASSERT(!initialized_);
|
||||||
|
|
||||||
|
std::vector<std::string> tokens;
|
||||||
|
talk_base::tokenize(config_, ' ', &tokens);
|
||||||
|
|
||||||
|
if (tokens.size() != kConfigTokens) {
|
||||||
|
LOG(LS_ERROR) << "Invalid config string";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
service_type_ = SERVICE_COUNT;
|
||||||
|
|
||||||
|
// NOTE: Must be in the same order as the enum.
|
||||||
|
static const char* kValidServiceTypes[SERVICE_COUNT] = {
|
||||||
|
"STUN", "STUNS","TURN", "TURNS"
|
||||||
|
};
|
||||||
|
const std::string& type = tokens[0];
|
||||||
|
for (size_t i = 0; i < SERVICE_COUNT; ++i) {
|
||||||
|
if (type.compare(kValidServiceTypes[i]) == 0) {
|
||||||
|
service_type_ = static_cast<ServiceType>(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (service_type_ == SERVICE_COUNT) {
|
||||||
|
LOG(LS_ERROR) << "Invalid service type: " << type;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
service_address_ = tokens[1];
|
||||||
|
|
||||||
|
int port;
|
||||||
|
tokens.clear();
|
||||||
|
talk_base::tokenize(service_address_, ':', &tokens);
|
||||||
|
if (tokens.size() != kConfigTokens) {
|
||||||
|
port = kDefaultStunPort;
|
||||||
|
} else {
|
||||||
|
port = atoi(tokens[1].c_str());
|
||||||
|
if (port <= 0 || port > 0xffff) {
|
||||||
|
LOG(LS_ERROR) << "Invalid port: " << tokens[1];
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
talk_base::SocketAddress stun_addr(tokens[0], port);
|
||||||
|
|
||||||
|
socket_factory_.reset(new talk_base::BasicPacketSocketFactory(
|
||||||
|
media_thread_.get()));
|
||||||
|
|
||||||
|
port_allocator_.reset(new cricket::BasicPortAllocator(network_manager_.get(),
|
||||||
|
stun_addr, talk_base::SocketAddress(), talk_base::SocketAddress(),
|
||||||
|
talk_base::SocketAddress()));
|
||||||
|
|
||||||
|
ASSERT(port_allocator_.get() != NULL);
|
||||||
|
port_allocator_->set_flags(cricket::PORTALLOCATOR_DISABLE_STUN |
|
||||||
|
cricket::PORTALLOCATOR_DISABLE_TCP |
|
||||||
|
cricket::PORTALLOCATOR_DISABLE_RELAY);
|
||||||
|
|
||||||
|
// create channel manager
|
||||||
|
channel_manager_.reset(new WebRtcChannelManager(media_thread_.get()));
|
||||||
|
|
||||||
|
//start the media thread
|
||||||
|
media_thread_->SetPriority(talk_base::PRIORITY_HIGH);
|
||||||
|
media_thread_->SetName("PeerConn", this);
|
||||||
|
if (!media_thread_->Start()) {
|
||||||
|
LOG(LS_ERROR) << "Failed to start media thread";
|
||||||
|
} else if (!channel_manager_->Init()) {
|
||||||
|
LOG(LS_ERROR) << "Failed to initialize the channel manager";
|
||||||
|
} if (!signaling_thread_->SetName("Session Signaling Thread", this) ||
|
||||||
|
!signaling_thread_->Start()) {
|
||||||
|
LOG(LS_ERROR) << "Failed to start session signaling thread";
|
||||||
|
} else {
|
||||||
|
initialized_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return initialized_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PeerConnection::RegisterObserver(PeerConnectionObserver* observer) {
|
||||||
|
// This assert is to catch cases where two observer pointers are registered.
|
||||||
|
// We only support one and if another is to be used, the current one must be
|
||||||
|
// cleared first.
|
||||||
|
ASSERT(observer == NULL || event_callback_ == NULL);
|
||||||
|
event_callback_ = observer;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PeerConnection::SignalingMessage(const std::string& signaling_message) {
|
||||||
|
// Deserialize signaling message
|
||||||
|
cricket::SessionDescription* incoming_sdp = NULL;
|
||||||
|
std::vector<cricket::Candidate> candidates;
|
||||||
|
if (!ParseJSONSignalingMessage(signaling_message, incoming_sdp, candidates))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
bool ret = false;
|
||||||
|
if (!session_) {
|
||||||
|
// this will be incoming call
|
||||||
|
std::string sid;
|
||||||
|
talk_base::CreateRandomString(8, &sid);
|
||||||
|
std::string direction("r");
|
||||||
|
session_ = CreateMediaSession(sid, direction);
|
||||||
|
ASSERT(session_ != NULL);
|
||||||
|
incoming_ = true;
|
||||||
|
ret = session_->OnInitiateMessage(incoming_sdp, candidates);
|
||||||
|
} else {
|
||||||
|
ret = session_->OnRemoteDescription(incoming_sdp, candidates);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
WebRTCSessionImpl* PeerConnection::CreateMediaSession(const std::string& id,
|
||||||
|
const std::string& dir) {
|
||||||
|
WebRTCSessionImpl* session = new WebRTCSessionImpl(id, dir,
|
||||||
|
port_allocator_.get(), channel_manager_.get(), this,
|
||||||
|
signaling_thread_.get());
|
||||||
|
if (session) {
|
||||||
|
session->SignalOnRemoveStream.connect(this,
|
||||||
|
&PeerConnection::SendRemoveSignal);
|
||||||
|
}
|
||||||
|
return session;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PeerConnection::SendRemoveSignal(WebRTCSessionImpl* session) {
|
||||||
|
if (event_callback_) {
|
||||||
|
std::string message;
|
||||||
|
if (GetJSONSignalingMessage(session->remote_description(),
|
||||||
|
session->local_candidates(), &message)) {
|
||||||
|
event_callback_->OnSignalingMessage(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PeerConnection::AddStream(const std::string& stream_id, bool video) {
|
||||||
|
if (!session_) {
|
||||||
|
// if session doesn't exist then this should be an outgoing call
|
||||||
|
std::string sid;
|
||||||
|
if (!talk_base::CreateRandomString(8, &sid) ||
|
||||||
|
(session_ = CreateMediaSession(sid, "s")) == NULL) {
|
||||||
|
ASSERT(false && "failed to initialize a session");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ret = false;
|
||||||
|
|
||||||
|
if (session_->HasStream(stream_id)) {
|
||||||
|
ASSERT(false && "A stream with this name already exists");
|
||||||
|
} else {
|
||||||
|
//TODO: we should ensure CreateVoiceChannel/CreateVideoChannel be called
|
||||||
|
// after transportchannel is ready
|
||||||
|
if (!video) {
|
||||||
|
ret = !session_->HasAudioStream() &&
|
||||||
|
session_->CreateP2PTransportChannel(stream_id, video) &&
|
||||||
|
session_->CreateVoiceChannel(stream_id);
|
||||||
|
} else {
|
||||||
|
ret = !session_->HasVideoStream() &&
|
||||||
|
session_->CreateP2PTransportChannel(stream_id, video) &&
|
||||||
|
session_->CreateVideoChannel(stream_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PeerConnection::RemoveStream(const std::string& stream_id) {
|
||||||
|
ASSERT(session_ != NULL);
|
||||||
|
return session_->RemoveStream(stream_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PeerConnection::OnLocalDescription(
|
||||||
|
cricket::SessionDescription* desc,
|
||||||
|
const std::vector<cricket::Candidate>& candidates) {
|
||||||
|
if (!desc) {
|
||||||
|
LOG(LS_ERROR) << "no local SDP ";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string message;
|
||||||
|
if (GetJSONSignalingMessage(desc, candidates, &message)) {
|
||||||
|
if (event_callback_) {
|
||||||
|
event_callback_->OnSignalingMessage(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PeerConnection::SetAudioDevice(const std::string& wave_in_device,
|
||||||
|
const std::string& wave_out_device, int opts) {
|
||||||
|
return channel_manager_->SetAudioOptions(wave_in_device, wave_out_device, opts);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PeerConnection::SetVideoRenderer(const std::string& stream_id,
|
||||||
|
ExternalRenderer* external_renderer) {
|
||||||
|
ASSERT(session_ != NULL);
|
||||||
|
return session_->SetVideoRenderer(stream_id, external_renderer);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PeerConnection::SetVideoRenderer(int channel_id,
|
||||||
|
void* window,
|
||||||
|
unsigned int zOrder,
|
||||||
|
float left,
|
||||||
|
float top,
|
||||||
|
float right,
|
||||||
|
float bottom) {
|
||||||
|
ASSERT(session_ != NULL);
|
||||||
|
return session_->SetVideoRenderer(channel_id, window, zOrder, left, top,
|
||||||
|
right, bottom);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PeerConnection::SetVideoCapture(const std::string& cam_device) {
|
||||||
|
return channel_manager_->SetVideoOptions(cam_device);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PeerConnection::Connect() {
|
||||||
|
return session_->Initiate();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PeerConnection::OnAddStream(const std::string& stream_id,
|
||||||
|
int channel_id,
|
||||||
|
bool video) {
|
||||||
|
if (event_callback_) {
|
||||||
|
event_callback_->OnAddStream(stream_id, channel_id, video);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PeerConnection::OnRemoveStream(const std::string& stream_id,
|
||||||
|
int channel_id,
|
||||||
|
bool video) {
|
||||||
|
if (event_callback_) {
|
||||||
|
event_callback_->OnRemoveStream(stream_id, channel_id, video);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PeerConnection::OnRtcMediaChannelCreated(const std::string& stream_id,
|
||||||
|
int channel_id,
|
||||||
|
bool video) {
|
||||||
|
if (event_callback_) {
|
||||||
|
event_callback_->OnAddStream(stream_id, channel_id, video);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PeerConnection::Close() {
|
||||||
|
if (session_)
|
||||||
|
session_->RemoveAllStreams();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace webrtc
|
||||||
153
third_party_mods/libjingle/source/talk/app/peerconnection.h
Normal file
153
third_party_mods/libjingle/source/talk/app/peerconnection.h
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
// Copyright 2011 Google Inc. All Rights Reserved.
|
||||||
|
// Author: mallinath@google.com (Mallinath Bareddy)
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef TALK_APP_WEBRTC_PEERCONNECTION_H_
|
||||||
|
#define TALK_APP_WEBRTC_PEERCONNECTION_H_
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include "talk/base/sigslot.h"
|
||||||
|
#include "talk/base/thread.h"
|
||||||
|
#include "talk/base/scoped_ptr.h"
|
||||||
|
#include "talk/base/basicpacketsocketfactory.h"
|
||||||
|
#include "talk/app/webrtcchannelmanager.h"
|
||||||
|
|
||||||
|
namespace Json {
|
||||||
|
class Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace cricket {
|
||||||
|
class BasicPortAllocator;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef PLATFORM_CHROMIUM
|
||||||
|
class P2PSocketDispatcher;
|
||||||
|
#endif // PLATFORM_CHROMIUM
|
||||||
|
|
||||||
|
namespace webrtc {
|
||||||
|
|
||||||
|
class AudioDeviceModule;
|
||||||
|
class ExternalRenderer;
|
||||||
|
class WebRTCSessionImpl;
|
||||||
|
|
||||||
|
class PeerConnectionObserver {
|
||||||
|
public:
|
||||||
|
virtual void OnError() = 0;
|
||||||
|
// serialized signaling message
|
||||||
|
virtual void OnSignalingMessage(const std::string& msg) = 0;
|
||||||
|
|
||||||
|
// Triggered when a remote peer accepts a media connection.
|
||||||
|
virtual void OnAddStream(const std::string& stream_id,
|
||||||
|
int channel_id,
|
||||||
|
bool video) = 0;
|
||||||
|
|
||||||
|
// Triggered when a remote peer closes a media stream.
|
||||||
|
virtual void OnRemoveStream(const std::string& stream_id,
|
||||||
|
int channel_id,
|
||||||
|
bool video) = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// Dtor protected as objects shouldn't be deleted via this interface.
|
||||||
|
~PeerConnectionObserver() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
class PeerConnection : public sigslot::has_slots<> {
|
||||||
|
public:
|
||||||
|
|
||||||
|
#ifdef PLATFORM_CHROMIUM
|
||||||
|
PeerConnection(const std::string& config,
|
||||||
|
P2PSocketDispatcher* p2p_socket_dispatcher);
|
||||||
|
#else
|
||||||
|
explicit PeerConnection(const std::string& config);
|
||||||
|
#endif // PLATFORM_CHROMIUM
|
||||||
|
|
||||||
|
~PeerConnection();
|
||||||
|
|
||||||
|
bool Init();
|
||||||
|
void RegisterObserver(PeerConnectionObserver* observer);
|
||||||
|
bool SignalingMessage(const std::string& msg);
|
||||||
|
bool AddStream(const std::string& stream_id, bool video);
|
||||||
|
bool RemoveStream(const std::string& stream_id);
|
||||||
|
bool Connect();
|
||||||
|
void Close();
|
||||||
|
|
||||||
|
// TODO(ronghuawu): This section will be modified to reuse the existing libjingle APIs.
|
||||||
|
// Set Audio device
|
||||||
|
bool SetAudioDevice(const std::string& wave_in_device,
|
||||||
|
const std::string& wave_out_device, int opts);
|
||||||
|
// Set the video renderer
|
||||||
|
bool SetVideoRenderer(const std::string& stream_id,
|
||||||
|
ExternalRenderer* external_renderer);
|
||||||
|
// Set channel_id to -1 for the local preview
|
||||||
|
bool SetVideoRenderer(int channel_id,
|
||||||
|
void* window,
|
||||||
|
unsigned int zOrder,
|
||||||
|
float left,
|
||||||
|
float top,
|
||||||
|
float right,
|
||||||
|
float bottom);
|
||||||
|
// Set video capture device
|
||||||
|
// For Chromium the cam_device should use the capture session id.
|
||||||
|
// For standalone app, cam_device is the camera name. It will try to
|
||||||
|
// set the default capture device when cam_device is "".
|
||||||
|
bool SetVideoCapture(const std::string& cam_device);
|
||||||
|
|
||||||
|
// Access to the members
|
||||||
|
const std::string& config() const { return config_; }
|
||||||
|
bool incoming() const { return incoming_; }
|
||||||
|
talk_base::Thread* media_thread() {
|
||||||
|
return media_thread_.get();
|
||||||
|
}
|
||||||
|
#ifdef PLATFORM_CHROMIUM
|
||||||
|
P2PSocketDispatcher* p2p_socket_dispatcher() {
|
||||||
|
return p2p_socket_dispatcher_;
|
||||||
|
}
|
||||||
|
#endif // PLATFORM_CHROMIUM
|
||||||
|
|
||||||
|
// Callbacks
|
||||||
|
void OnAddStream(const std::string& stream_id, int channel_id, bool video);
|
||||||
|
void OnRemoveStream(const std::string& stream_id, int channel_id,
|
||||||
|
bool video);
|
||||||
|
void OnLocalDescription(cricket::SessionDescription* desc,
|
||||||
|
const std::vector<cricket::Candidate>& candidates);
|
||||||
|
void OnRtcMediaChannelCreated(const std::string& stream_id,
|
||||||
|
int channel_id,
|
||||||
|
bool video);
|
||||||
|
private:
|
||||||
|
void SendRemoveSignal(WebRTCSessionImpl* session);
|
||||||
|
WebRTCSessionImpl* CreateMediaSession(const std::string& id,
|
||||||
|
const std::string& dir);
|
||||||
|
|
||||||
|
std::string config_;
|
||||||
|
talk_base::scoped_ptr<talk_base::Thread> media_thread_;
|
||||||
|
talk_base::scoped_ptr<WebRtcChannelManager> channel_manager_;
|
||||||
|
talk_base::scoped_ptr<talk_base::NetworkManager> network_manager_;
|
||||||
|
talk_base::scoped_ptr<cricket::BasicPortAllocator> port_allocator_;
|
||||||
|
talk_base::scoped_ptr<talk_base::BasicPacketSocketFactory> socket_factory_;
|
||||||
|
talk_base::scoped_ptr<talk_base::Thread> signaling_thread_;
|
||||||
|
bool initialized_;
|
||||||
|
|
||||||
|
// NOTE: The order of the enum values must be in sync with the array
|
||||||
|
// in Init().
|
||||||
|
enum ServiceType {
|
||||||
|
STUN,
|
||||||
|
STUNS,
|
||||||
|
TURN,
|
||||||
|
TURNS,
|
||||||
|
SERVICE_COUNT, // Also means 'invalid'.
|
||||||
|
};
|
||||||
|
|
||||||
|
ServiceType service_type_;
|
||||||
|
std::string service_address_;
|
||||||
|
PeerConnectionObserver* event_callback_;
|
||||||
|
WebRTCSessionImpl* session_;
|
||||||
|
bool incoming_;
|
||||||
|
|
||||||
|
#ifdef PLATFORM_CHROMIUM
|
||||||
|
P2PSocketDispatcher* p2p_socket_dispatcher_;
|
||||||
|
#endif // PLATFORM_CHROMIUM
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* TALK_APP_WEBRTC_PEERCONNECTION_H_ */
|
||||||
@ -0,0 +1,389 @@
|
|||||||
|
// Copyright 2011 Google Inc. All Rights Reserved.
|
||||||
|
// Author: tommi@google.com (Tomas Gunnarsson)
|
||||||
|
|
||||||
|
#include "talk/app/session_test/main_wnd.h"
|
||||||
|
|
||||||
|
#include "talk/base/common.h"
|
||||||
|
#include "talk/base/logging.h"
|
||||||
|
|
||||||
|
ATOM MainWnd::wnd_class_ = 0;
|
||||||
|
const wchar_t MainWnd::kClassName[] = L"WebRTC_MainWnd";
|
||||||
|
|
||||||
|
// TODO(tommi): declare in header:
|
||||||
|
std::string GetDefaultServerName();
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
void CalculateWindowSizeForText(HWND wnd, const wchar_t* text,
|
||||||
|
size_t* width, size_t* height) {
|
||||||
|
HDC dc = ::GetDC(wnd);
|
||||||
|
RECT text_rc = {0};
|
||||||
|
::DrawText(dc, text, -1, &text_rc, DT_CALCRECT | DT_SINGLELINE);
|
||||||
|
::ReleaseDC(wnd, dc);
|
||||||
|
RECT client, window;
|
||||||
|
::GetClientRect(wnd, &client);
|
||||||
|
::GetWindowRect(wnd, &window);
|
||||||
|
|
||||||
|
*width = text_rc.right - text_rc.left;
|
||||||
|
*width += (window.right - window.left) -
|
||||||
|
(client.right - client.left);
|
||||||
|
*height = text_rc.bottom - text_rc.top;
|
||||||
|
*height += (window.bottom - window.top) -
|
||||||
|
(client.bottom - client.top);
|
||||||
|
}
|
||||||
|
|
||||||
|
HFONT GetDefaultFont() {
|
||||||
|
static HFONT font = reinterpret_cast<HFONT>(GetStockObject(DEFAULT_GUI_FONT));
|
||||||
|
return font;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string GetWindowText(HWND wnd) {
|
||||||
|
char text[MAX_PATH] = {0};
|
||||||
|
::GetWindowTextA(wnd, &text[0], ARRAYSIZE(text));
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddListBoxItem(HWND listbox, const std::string& str, LPARAM item_data) {
|
||||||
|
LRESULT index = ::SendMessageA(listbox, LB_ADDSTRING, 0,
|
||||||
|
reinterpret_cast<LPARAM>(str.c_str()));
|
||||||
|
::SendMessageA(listbox, LB_SETITEMDATA, index, item_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
MainWnd::MainWnd()
|
||||||
|
: ui_(CONNECT_TO_SERVER), wnd_(NULL), edit1_(NULL), edit2_(NULL),
|
||||||
|
label1_(NULL), label2_(NULL), button_(NULL), listbox_(NULL),
|
||||||
|
destroyed_(false), callback_(NULL), nested_msg_(NULL) {
|
||||||
|
}
|
||||||
|
|
||||||
|
MainWnd::~MainWnd() {
|
||||||
|
ASSERT(!IsWindow());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MainWnd::Create() {
|
||||||
|
ASSERT(wnd_ == NULL);
|
||||||
|
if (!RegisterWindowClass())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
wnd_ = ::CreateWindowExW(WS_EX_OVERLAPPEDWINDOW, kClassName, L"WebRTC",
|
||||||
|
WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_CLIPCHILDREN,
|
||||||
|
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
|
||||||
|
NULL, NULL, GetModuleHandle(NULL), this);
|
||||||
|
|
||||||
|
::SendMessage(wnd_, WM_SETFONT, reinterpret_cast<WPARAM>(GetDefaultFont()),
|
||||||
|
TRUE);
|
||||||
|
|
||||||
|
CreateChildWindows();
|
||||||
|
SwitchToConnectUI();
|
||||||
|
|
||||||
|
return wnd_ != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MainWnd::Destroy() {
|
||||||
|
BOOL ret = FALSE;
|
||||||
|
if (IsWindow()) {
|
||||||
|
ret = ::DestroyWindow(wnd_);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret != FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWnd::RegisterObserver(MainWndCallback* callback) {
|
||||||
|
callback_ = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MainWnd::IsWindow() const {
|
||||||
|
return wnd_ && ::IsWindow(wnd_) != FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MainWnd::PreTranslateMessage(MSG* msg) {
|
||||||
|
bool ret = false;
|
||||||
|
if (msg->message == WM_CHAR) {
|
||||||
|
if (msg->wParam == VK_TAB) {
|
||||||
|
HandleTabbing();
|
||||||
|
ret = true;
|
||||||
|
} else if (msg->wParam == VK_RETURN) {
|
||||||
|
OnDefaultAction();
|
||||||
|
ret = true;
|
||||||
|
} else if (msg->wParam == VK_ESCAPE) {
|
||||||
|
if (callback_) {
|
||||||
|
if (ui_ == STREAMING) {
|
||||||
|
callback_->DisconnectFromCurrentPeer();
|
||||||
|
} else {
|
||||||
|
callback_->DisconnectFromServer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWnd::SwitchToConnectUI() {
|
||||||
|
ASSERT(IsWindow());
|
||||||
|
LayoutPeerListUI(false);
|
||||||
|
ui_ = CONNECT_TO_SERVER;
|
||||||
|
LayoutConnectUI(true);
|
||||||
|
::SetFocus(edit1_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWnd::SwitchToPeerList(const Peers& peers) {
|
||||||
|
LayoutConnectUI(false);
|
||||||
|
|
||||||
|
::SendMessage(listbox_, LB_RESETCONTENT, 0, 0);
|
||||||
|
|
||||||
|
AddListBoxItem(listbox_, "List of currently connected peers:", -1);
|
||||||
|
Peers::const_iterator i = peers.begin();
|
||||||
|
for (; i != peers.end(); ++i)
|
||||||
|
AddListBoxItem(listbox_, i->second.c_str(), i->first);
|
||||||
|
|
||||||
|
ui_ = LIST_PEERS;
|
||||||
|
LayoutPeerListUI(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWnd::SwitchToStreamingUI() {
|
||||||
|
LayoutConnectUI(false);
|
||||||
|
LayoutPeerListUI(false);
|
||||||
|
ui_ = STREAMING;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWnd::OnPaint() {
|
||||||
|
PAINTSTRUCT ps;
|
||||||
|
::BeginPaint(handle(), &ps);
|
||||||
|
|
||||||
|
RECT rc;
|
||||||
|
::GetClientRect(handle(), &rc);
|
||||||
|
HBRUSH brush = ::CreateSolidBrush(::GetSysColor(COLOR_WINDOW));
|
||||||
|
::FillRect(ps.hdc, &rc, brush);
|
||||||
|
::DeleteObject(brush);
|
||||||
|
|
||||||
|
::EndPaint(handle(), &ps);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWnd::OnDestroyed() {
|
||||||
|
PostQuitMessage(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWnd::OnDefaultAction() {
|
||||||
|
if (!callback_)
|
||||||
|
return;
|
||||||
|
if (ui_ == CONNECT_TO_SERVER) {
|
||||||
|
std::string server(GetWindowText(edit1_));
|
||||||
|
std::string port_str(GetWindowText(edit2_));
|
||||||
|
int port = port_str.length() ? atoi(port_str.c_str()) : 0;
|
||||||
|
callback_->StartLogin(server, port);
|
||||||
|
} else if (ui_ == LIST_PEERS) {
|
||||||
|
LRESULT sel = ::SendMessage(listbox_, LB_GETCURSEL, 0, 0);
|
||||||
|
if (sel != LB_ERR) {
|
||||||
|
LRESULT peer_id = ::SendMessage(listbox_, LB_GETITEMDATA, sel, 0);
|
||||||
|
if (peer_id != -1 && callback_) {
|
||||||
|
callback_->ConnectToPeer(peer_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
MessageBoxA(wnd_, "OK!", "Yeah", MB_OK);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MainWnd::OnMessage(UINT msg, WPARAM wp, LPARAM lp, LRESULT* result) {
|
||||||
|
switch (msg) {
|
||||||
|
case WM_ERASEBKGND:
|
||||||
|
*result = TRUE;
|
||||||
|
return true;
|
||||||
|
case WM_PAINT:
|
||||||
|
OnPaint();
|
||||||
|
return true;
|
||||||
|
case WM_SETFOCUS:
|
||||||
|
if (ui_ == CONNECT_TO_SERVER) {
|
||||||
|
SetFocus(edit1_);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
case WM_SIZE:
|
||||||
|
if (ui_ == CONNECT_TO_SERVER) {
|
||||||
|
LayoutConnectUI(true);
|
||||||
|
} else if (ui_ == LIST_PEERS) {
|
||||||
|
LayoutPeerListUI(true);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case WM_CTLCOLORSTATIC:
|
||||||
|
*result = reinterpret_cast<LRESULT>(GetSysColorBrush(COLOR_WINDOW));
|
||||||
|
return true;
|
||||||
|
case WM_COMMAND:
|
||||||
|
if (button_ == reinterpret_cast<HWND>(lp)) {
|
||||||
|
if (BN_CLICKED == HIWORD(wp))
|
||||||
|
OnDefaultAction();
|
||||||
|
} else if (listbox_ == reinterpret_cast<HWND>(lp)) {
|
||||||
|
if (LBN_DBLCLK == HIWORD(wp)) {
|
||||||
|
OnDefaultAction();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
LRESULT CALLBACK MainWnd::WndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) {
|
||||||
|
MainWnd* me = reinterpret_cast<MainWnd*>(
|
||||||
|
::GetWindowLongPtr(hwnd, GWL_USERDATA));
|
||||||
|
if (!me && WM_CREATE == msg) {
|
||||||
|
CREATESTRUCT* cs = reinterpret_cast<CREATESTRUCT*>(lp);
|
||||||
|
me = reinterpret_cast<MainWnd*>(cs->lpCreateParams);
|
||||||
|
me->wnd_ = hwnd;
|
||||||
|
::SetWindowLongPtr(hwnd, GWL_USERDATA, reinterpret_cast<LONG_PTR>(me));
|
||||||
|
}
|
||||||
|
|
||||||
|
LRESULT result = 0;
|
||||||
|
if (me) {
|
||||||
|
void* prev_nested_msg = me->nested_msg_;
|
||||||
|
me->nested_msg_ = &msg;
|
||||||
|
|
||||||
|
bool handled = me->OnMessage(msg, wp, lp, &result);
|
||||||
|
if (WM_NCDESTROY == msg) {
|
||||||
|
me->destroyed_ = true;
|
||||||
|
} else if (!handled) {
|
||||||
|
result = ::DefWindowProc(hwnd, msg, wp, lp);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (me->destroyed_ && prev_nested_msg == NULL) {
|
||||||
|
me->OnDestroyed();
|
||||||
|
me->wnd_ = NULL;
|
||||||
|
me->destroyed_ = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
me->nested_msg_ = prev_nested_msg;
|
||||||
|
} else {
|
||||||
|
result = ::DefWindowProc(hwnd, msg, wp, lp);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// static
|
||||||
|
bool MainWnd::RegisterWindowClass() {
|
||||||
|
if (wnd_class_)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
WNDCLASSEX wcex = { sizeof(WNDCLASSEX) };
|
||||||
|
wcex.style = CS_DBLCLKS;
|
||||||
|
wcex.hInstance = GetModuleHandle(NULL);
|
||||||
|
wcex.hbrBackground = reinterpret_cast<HBRUSH>(COLOR_WINDOW + 1);
|
||||||
|
wcex.hCursor = ::LoadCursor(NULL, IDC_ARROW);
|
||||||
|
wcex.lpfnWndProc = &WndProc;
|
||||||
|
wcex.lpszClassName = kClassName;
|
||||||
|
wnd_class_ = ::RegisterClassEx(&wcex);
|
||||||
|
ASSERT(wnd_class_);
|
||||||
|
return wnd_class_ != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWnd::CreateChildWindow(HWND* wnd, MainWnd::ChildWindowID id,
|
||||||
|
const wchar_t* class_name, DWORD control_style,
|
||||||
|
DWORD ex_style) {
|
||||||
|
if (::IsWindow(*wnd))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Child windows are invisible at first, and shown after being resized.
|
||||||
|
DWORD style = WS_CHILD | control_style;
|
||||||
|
*wnd = ::CreateWindowEx(ex_style, class_name, L"", style,
|
||||||
|
100, 100, 100, 100, wnd_,
|
||||||
|
reinterpret_cast<HMENU>(id),
|
||||||
|
GetModuleHandle(NULL), NULL);
|
||||||
|
ASSERT(::IsWindow(*wnd));
|
||||||
|
::SendMessage(*wnd, WM_SETFONT, reinterpret_cast<WPARAM>(GetDefaultFont()),
|
||||||
|
TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWnd::CreateChildWindows() {
|
||||||
|
// Create the child windows in tab order.
|
||||||
|
CreateChildWindow(&label1_, LABEL1_ID, L"Static", ES_CENTER | ES_READONLY, 0);
|
||||||
|
CreateChildWindow(&edit1_, EDIT_ID, L"Edit",
|
||||||
|
ES_LEFT | ES_NOHIDESEL | WS_TABSTOP, WS_EX_CLIENTEDGE);
|
||||||
|
CreateChildWindow(&label2_, LABEL2_ID, L"Static", ES_CENTER | ES_READONLY, 0);
|
||||||
|
CreateChildWindow(&edit2_, EDIT_ID, L"Edit",
|
||||||
|
ES_LEFT | ES_NOHIDESEL | WS_TABSTOP, WS_EX_CLIENTEDGE);
|
||||||
|
CreateChildWindow(&button_, BUTTON_ID, L"Button", BS_CENTER | WS_TABSTOP, 0);
|
||||||
|
|
||||||
|
CreateChildWindow(&listbox_, LISTBOX_ID, L"ListBox",
|
||||||
|
LBS_HASSTRINGS | LBS_NOTIFY, WS_EX_CLIENTEDGE);
|
||||||
|
|
||||||
|
::SetWindowTextA(edit1_, GetDefaultServerName().c_str());
|
||||||
|
::SetWindowTextA(edit2_, "8888");
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWnd::LayoutConnectUI(bool show) {
|
||||||
|
struct Windows {
|
||||||
|
HWND wnd;
|
||||||
|
const wchar_t* text;
|
||||||
|
size_t width;
|
||||||
|
size_t height;
|
||||||
|
} windows[] = {
|
||||||
|
{ label1_, L"Server" },
|
||||||
|
{ edit1_, L"XXXyyyYYYgggXXXyyyYYYggg" },
|
||||||
|
{ label2_, L":" },
|
||||||
|
{ edit2_, L"XyXyX" },
|
||||||
|
{ button_, L"Connect" },
|
||||||
|
};
|
||||||
|
|
||||||
|
if (show) {
|
||||||
|
const size_t kSeparator = 5;
|
||||||
|
size_t total_width = (ARRAYSIZE(windows) - 1) * kSeparator;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < ARRAYSIZE(windows); ++i) {
|
||||||
|
CalculateWindowSizeForText(windows[i].wnd, windows[i].text,
|
||||||
|
&windows[i].width, &windows[i].height);
|
||||||
|
total_width += windows[i].width;
|
||||||
|
}
|
||||||
|
|
||||||
|
RECT rc;
|
||||||
|
::GetClientRect(wnd_, &rc);
|
||||||
|
size_t x = (rc.right / 2) - (total_width / 2);
|
||||||
|
size_t y = rc.bottom / 2;
|
||||||
|
for (size_t i = 0; i < ARRAYSIZE(windows); ++i) {
|
||||||
|
size_t top = y - (windows[i].height / 2);
|
||||||
|
::MoveWindow(windows[i].wnd, x, top, windows[i].width, windows[i].height,
|
||||||
|
TRUE);
|
||||||
|
x += kSeparator + windows[i].width;
|
||||||
|
if (windows[i].text[0] != 'X')
|
||||||
|
::SetWindowText(windows[i].wnd, windows[i].text);
|
||||||
|
::ShowWindow(windows[i].wnd, SW_SHOWNA);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (size_t i = 0; i < ARRAYSIZE(windows); ++i) {
|
||||||
|
::ShowWindow(windows[i].wnd, SW_HIDE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWnd::LayoutPeerListUI(bool show) {
|
||||||
|
if (show) {
|
||||||
|
RECT rc;
|
||||||
|
::GetClientRect(wnd_, &rc);
|
||||||
|
::MoveWindow(listbox_, 0, 0, rc.right, rc.bottom, TRUE);
|
||||||
|
::ShowWindow(listbox_, SW_SHOWNA);
|
||||||
|
} else {
|
||||||
|
::ShowWindow(listbox_, SW_HIDE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWnd::HandleTabbing() {
|
||||||
|
bool shift = ((::GetAsyncKeyState(VK_SHIFT) & 0x8000) != 0);
|
||||||
|
UINT next_cmd = shift ? GW_HWNDPREV : GW_HWNDNEXT;
|
||||||
|
UINT loop_around_cmd = shift ? GW_HWNDLAST : GW_HWNDFIRST;
|
||||||
|
HWND focus = GetFocus(), next;
|
||||||
|
do {
|
||||||
|
next = ::GetWindow(focus, next_cmd);
|
||||||
|
if (IsWindowVisible(next) &&
|
||||||
|
(GetWindowLong(next, GWL_STYLE) & WS_TABSTOP)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!next) {
|
||||||
|
next = ::GetWindow(focus, loop_around_cmd);
|
||||||
|
if (IsWindowVisible(next) &&
|
||||||
|
(GetWindowLong(next, GWL_STYLE) & WS_TABSTOP)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
focus = next;
|
||||||
|
} while (true);
|
||||||
|
::SetFocus(next);
|
||||||
|
}
|
||||||
@ -0,0 +1,96 @@
|
|||||||
|
// Copyright 2011 Google Inc. All Rights Reserved.
|
||||||
|
// Author: tommi@google.com (Tomas Gunnarsson)
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef TALK_APP_SESSION_TEST_MAIN_WND_H_
|
||||||
|
#define TALK_APP_SESSION_TEST_MAIN_WND_H_
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "talk/base/win32.h"
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
// TODO(tommi): Move to same header as PeerConnectionClient.
|
||||||
|
typedef std::map<int, std::string> Peers;
|
||||||
|
|
||||||
|
|
||||||
|
class MainWndCallback {
|
||||||
|
public:
|
||||||
|
virtual void StartLogin(const std::string& server, int port) = 0;
|
||||||
|
virtual void DisconnectFromServer() = 0;
|
||||||
|
virtual void ConnectToPeer(int peer_id) = 0;
|
||||||
|
virtual void DisconnectFromCurrentPeer() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class MainWnd {
|
||||||
|
public:
|
||||||
|
static const wchar_t kClassName[];
|
||||||
|
|
||||||
|
enum UI {
|
||||||
|
CONNECT_TO_SERVER,
|
||||||
|
LIST_PEERS,
|
||||||
|
STREAMING,
|
||||||
|
};
|
||||||
|
|
||||||
|
MainWnd();
|
||||||
|
~MainWnd();
|
||||||
|
|
||||||
|
bool Create();
|
||||||
|
bool Destroy();
|
||||||
|
bool IsWindow() const;
|
||||||
|
|
||||||
|
void RegisterObserver(MainWndCallback* callback);
|
||||||
|
|
||||||
|
bool PreTranslateMessage(MSG* msg);
|
||||||
|
|
||||||
|
void SwitchToConnectUI();
|
||||||
|
void SwitchToPeerList(const Peers& peers);
|
||||||
|
void SwitchToStreamingUI();
|
||||||
|
|
||||||
|
HWND handle() const { return wnd_; }
|
||||||
|
UI current_ui() const { return ui_; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
enum ChildWindowID {
|
||||||
|
EDIT_ID = 1,
|
||||||
|
BUTTON_ID,
|
||||||
|
LABEL1_ID,
|
||||||
|
LABEL2_ID,
|
||||||
|
LISTBOX_ID,
|
||||||
|
};
|
||||||
|
|
||||||
|
void OnPaint();
|
||||||
|
void OnDestroyed();
|
||||||
|
|
||||||
|
void OnDefaultAction();
|
||||||
|
|
||||||
|
bool OnMessage(UINT msg, WPARAM wp, LPARAM lp, LRESULT* result);
|
||||||
|
|
||||||
|
static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp);
|
||||||
|
static bool RegisterWindowClass();
|
||||||
|
|
||||||
|
void CreateChildWindow(HWND* wnd, ChildWindowID id, const wchar_t* class_name,
|
||||||
|
DWORD control_style, DWORD ex_style);
|
||||||
|
void CreateChildWindows();
|
||||||
|
|
||||||
|
void LayoutConnectUI(bool show);
|
||||||
|
void LayoutPeerListUI(bool show);
|
||||||
|
|
||||||
|
void HandleTabbing();
|
||||||
|
|
||||||
|
private:
|
||||||
|
UI ui_;
|
||||||
|
HWND wnd_;
|
||||||
|
HWND edit1_;
|
||||||
|
HWND edit2_;
|
||||||
|
HWND label1_;
|
||||||
|
HWND label2_;
|
||||||
|
HWND button_;
|
||||||
|
HWND listbox_;
|
||||||
|
bool destroyed_;
|
||||||
|
void* nested_msg_;
|
||||||
|
MainWndCallback* callback_;
|
||||||
|
static ATOM wnd_class_;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // TALK_APP_SESSION_TEST_MAIN_WND_H_
|
||||||
@ -0,0 +1,850 @@
|
|||||||
|
// Copyright 2011 Google Inc. All Rights Reserved.
|
||||||
|
// Author: tommi@google.com (Tomas Gunnarsson)
|
||||||
|
|
||||||
|
// This may not look like much but it has already uncovered several issues.
|
||||||
|
// In the future this will be a p2p reference app for the webrtc API along
|
||||||
|
// with a separate simple server implementation.
|
||||||
|
|
||||||
|
#include "talk/base/win32.h" // Must be first
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
#include "talk/base/scoped_ptr.h"
|
||||||
|
#include "talk/base/win32socketinit.cc"
|
||||||
|
#include "talk/base/win32socketserver.h" // For Win32Socket
|
||||||
|
#include "talk/base/win32socketserver.cc" // For Win32Socket
|
||||||
|
|
||||||
|
#include "modules/audio_device/main/interface/audio_device.h"
|
||||||
|
#include "modules/video_capture/main/interface/video_capture.h"
|
||||||
|
#include "system_wrappers/source/trace_impl.h"
|
||||||
|
#include "talk/app/peerconnection.h"
|
||||||
|
#include "talk/app/session_test/main_wnd.h"
|
||||||
|
#include "talk/base/logging.h"
|
||||||
|
|
||||||
|
static const char kAudioLabel[] = "audio_label";
|
||||||
|
static const char kVideoLabel[] = "video_label";
|
||||||
|
const unsigned short kDefaultServerPort = 8888;
|
||||||
|
|
||||||
|
using talk_base::scoped_ptr;
|
||||||
|
using webrtc::AudioDeviceModule;
|
||||||
|
using webrtc::PeerConnection;
|
||||||
|
using webrtc::PeerConnectionObserver;
|
||||||
|
|
||||||
|
std::string GetEnvVarOrDefault(const char* env_var_name,
|
||||||
|
const char* default_value) {
|
||||||
|
std::string value;
|
||||||
|
const char* env_var = getenv(env_var_name);
|
||||||
|
if (env_var)
|
||||||
|
value = env_var;
|
||||||
|
|
||||||
|
if (value.empty())
|
||||||
|
value = default_value;
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string GetPeerConnectionString() {
|
||||||
|
return GetEnvVarOrDefault("WEBRTC_CONNECT", "STUN stun.l.google.com:19302");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string GetDefaultServerName() {
|
||||||
|
return GetEnvVarOrDefault("WEBRTC_SERVER", "localhost");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string GetPeerName() {
|
||||||
|
char computer_name[MAX_PATH] = {0}, user_name[MAX_PATH] = {0};
|
||||||
|
DWORD size = ARRAYSIZE(computer_name);
|
||||||
|
::GetComputerNameA(computer_name, &size);
|
||||||
|
size = ARRAYSIZE(user_name);
|
||||||
|
::GetUserNameA(user_name, &size);
|
||||||
|
std::string ret(user_name);
|
||||||
|
ret += '@';
|
||||||
|
ret += computer_name;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct PeerConnectionClientObserver {
|
||||||
|
virtual void OnSignedIn() = 0; // Called when we're "logged" on.
|
||||||
|
virtual void OnDisconnected() = 0;
|
||||||
|
virtual void OnPeerConnected(int id, const std::string& name) = 0;
|
||||||
|
virtual void OnPeerDisconnected(int id, const std::string& name) = 0;
|
||||||
|
virtual void OnMessageFromPeer(int peer_id, const std::string& message) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class PeerConnectionClient : public sigslot::has_slots<> {
|
||||||
|
public:
|
||||||
|
enum State {
|
||||||
|
NOT_CONNECTED,
|
||||||
|
SIGNING_IN,
|
||||||
|
CONNECTED,
|
||||||
|
SIGNING_OUT_WAITING,
|
||||||
|
SIGNING_OUT,
|
||||||
|
};
|
||||||
|
|
||||||
|
PeerConnectionClient() : callback_(NULL), my_id_(-1), state_(NOT_CONNECTED) {
|
||||||
|
control_socket_.SignalCloseEvent.connect(this,
|
||||||
|
&PeerConnectionClient::OnClose);
|
||||||
|
hanging_get_.SignalCloseEvent.connect(this,
|
||||||
|
&PeerConnectionClient::OnClose);
|
||||||
|
control_socket_.SignalConnectEvent.connect(this,
|
||||||
|
&PeerConnectionClient::OnConnect);
|
||||||
|
hanging_get_.SignalConnectEvent.connect(this,
|
||||||
|
&PeerConnectionClient::OnHangingGetConnect);
|
||||||
|
control_socket_.SignalReadEvent.connect(this,
|
||||||
|
&PeerConnectionClient::OnRead);
|
||||||
|
hanging_get_.SignalReadEvent.connect(this,
|
||||||
|
&PeerConnectionClient::OnHangingGetRead);
|
||||||
|
}
|
||||||
|
|
||||||
|
~PeerConnectionClient() {
|
||||||
|
}
|
||||||
|
|
||||||
|
int id() const {
|
||||||
|
return my_id_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_connected() const {
|
||||||
|
return my_id_ != -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Peers& peers() const {
|
||||||
|
return peers_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RegisterObserver(PeerConnectionClientObserver* callback) {
|
||||||
|
ASSERT(!callback_);
|
||||||
|
callback_ = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Connect(const std::string& server, int port,
|
||||||
|
const std::string& client_name) {
|
||||||
|
ASSERT(!server.empty());
|
||||||
|
ASSERT(!client_name.empty());
|
||||||
|
ASSERT(state_ == NOT_CONNECTED);
|
||||||
|
|
||||||
|
if (server.empty() || client_name.empty())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (port <= 0)
|
||||||
|
port = kDefaultServerPort;
|
||||||
|
|
||||||
|
server_address_.SetIP(server);
|
||||||
|
server_address_.SetPort(port);
|
||||||
|
|
||||||
|
if (server_address_.IsUnresolved()) {
|
||||||
|
hostent* h = gethostbyname(server_address_.IPAsString().c_str());
|
||||||
|
if (!h) {
|
||||||
|
LOG(LS_ERROR) << "Failed to resolve host name: "
|
||||||
|
<< server_address_.IPAsString();
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
server_address_.SetResolvedIP(
|
||||||
|
ntohl(*reinterpret_cast<uint32*>(h->h_addr_list[0])));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char buffer[1024];
|
||||||
|
wsprintfA(buffer, "GET /sign_in?%s HTTP/1.0\r\n\r\n", client_name.c_str());
|
||||||
|
onconnect_data_ = buffer;
|
||||||
|
|
||||||
|
bool ret = ConnectControlSocket();
|
||||||
|
if (ret)
|
||||||
|
state_ = SIGNING_IN;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SendToPeer(int peer_id, const std::string& message) {
|
||||||
|
if (state_ != CONNECTED)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
ASSERT(is_connected());
|
||||||
|
ASSERT(control_socket_.GetState() == talk_base::Socket::CS_CLOSED);
|
||||||
|
if (!is_connected() || peer_id == -1)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
char headers[1024];
|
||||||
|
wsprintfA(headers, "POST /message?peer_id=%i&to=%i HTTP/1.0\r\n"
|
||||||
|
"Content-Length: %i\r\n"
|
||||||
|
"Content-Type: text/plain\r\n"
|
||||||
|
"\r\n",
|
||||||
|
my_id_, peer_id, message.length());
|
||||||
|
onconnect_data_ = headers;
|
||||||
|
onconnect_data_ += message;
|
||||||
|
return ConnectControlSocket();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SignOut() {
|
||||||
|
if (state_ == NOT_CONNECTED || state_ == SIGNING_OUT)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (hanging_get_.GetState() != talk_base::Socket::CS_CLOSED)
|
||||||
|
hanging_get_.Close();
|
||||||
|
|
||||||
|
if (control_socket_.GetState() == talk_base::Socket::CS_CLOSED) {
|
||||||
|
ASSERT(my_id_ != -1);
|
||||||
|
state_ = SIGNING_OUT;
|
||||||
|
|
||||||
|
char buffer[1024];
|
||||||
|
wsprintfA(buffer, "GET /sign_out?peer_id=%i HTTP/1.0\r\n\r\n", my_id_);
|
||||||
|
onconnect_data_ = buffer;
|
||||||
|
return ConnectControlSocket();
|
||||||
|
} else {
|
||||||
|
state_ = SIGNING_OUT_WAITING;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void Close() {
|
||||||
|
control_socket_.Close();
|
||||||
|
hanging_get_.Close();
|
||||||
|
onconnect_data_.clear();
|
||||||
|
peers_.clear();
|
||||||
|
my_id_ = -1;
|
||||||
|
state_ = NOT_CONNECTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ConnectControlSocket() {
|
||||||
|
ASSERT(control_socket_.GetState() == talk_base::Socket::CS_CLOSED);
|
||||||
|
int err = control_socket_.Connect(server_address_);
|
||||||
|
if (err == SOCKET_ERROR) {
|
||||||
|
Close();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnConnect(talk_base::AsyncSocket* socket) {
|
||||||
|
int sent = socket->Send(onconnect_data_.c_str(), onconnect_data_.length());
|
||||||
|
ASSERT(sent == onconnect_data_.length());
|
||||||
|
onconnect_data_.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnHangingGetConnect(talk_base::AsyncSocket* socket) {
|
||||||
|
char buffer[1024];
|
||||||
|
wsprintfA(buffer, "GET /wait?peer_id=%i HTTP/1.0\r\n\r\n", my_id_);
|
||||||
|
int len = lstrlenA(buffer);
|
||||||
|
int sent = socket->Send(buffer, len);
|
||||||
|
ASSERT(sent == len);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Quick and dirty support for parsing HTTP header values.
|
||||||
|
bool GetHeaderValue(const std::string& data, size_t eoh,
|
||||||
|
const char* header_pattern, size_t* value) {
|
||||||
|
ASSERT(value);
|
||||||
|
size_t found = data.find(header_pattern);
|
||||||
|
if (found != std::string::npos && found < eoh) {
|
||||||
|
*value = atoi(&data[found + lstrlenA(header_pattern)]);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GetHeaderValue(const std::string& data, size_t eoh,
|
||||||
|
const char* header_pattern, std::string* value) {
|
||||||
|
ASSERT(value);
|
||||||
|
size_t found = data.find(header_pattern);
|
||||||
|
if (found != std::string::npos && found < eoh) {
|
||||||
|
size_t begin = found + lstrlenA(header_pattern);
|
||||||
|
size_t end = data.find("\r\n", begin);
|
||||||
|
if (end == std::string::npos)
|
||||||
|
end = eoh;
|
||||||
|
value->assign(data.substr(begin, end - begin));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns true if the whole response has been read.
|
||||||
|
bool ReadIntoBuffer(talk_base::AsyncSocket* socket, std::string* data,
|
||||||
|
size_t* content_length) {
|
||||||
|
LOG(INFO) << __FUNCTION__;
|
||||||
|
|
||||||
|
char buffer[0xffff];
|
||||||
|
do {
|
||||||
|
int bytes = socket->Recv(buffer, sizeof(buffer));
|
||||||
|
if (bytes <= 0)
|
||||||
|
break;
|
||||||
|
data->append(buffer, bytes);
|
||||||
|
} while (true);
|
||||||
|
|
||||||
|
bool ret = false;
|
||||||
|
size_t i = data->find("\r\n\r\n");
|
||||||
|
if (i != std::string::npos) {
|
||||||
|
LOG(INFO) << "Headers received";
|
||||||
|
const char kContentLengthHeader[] = "\r\nContent-Length: ";
|
||||||
|
if (GetHeaderValue(*data, i, "\r\nContent-Length: ", content_length)) {
|
||||||
|
LOG(INFO) << "Expecting " << *content_length << " bytes.";
|
||||||
|
size_t total_response_size = (i + 4) + *content_length;
|
||||||
|
if (data->length() >= total_response_size) {
|
||||||
|
ret = true;
|
||||||
|
std::string should_close;
|
||||||
|
const char kConnection[] = "\r\nConnection: ";
|
||||||
|
if (GetHeaderValue(*data, i, kConnection, &should_close) &&
|
||||||
|
should_close.compare("close") == 0) {
|
||||||
|
socket->Close();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// We haven't received everything. Just continue to accept data.
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LOG(LS_ERROR) << "No content length field specified by the server.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnRead(talk_base::AsyncSocket* socket) {
|
||||||
|
LOG(INFO) << __FUNCTION__;
|
||||||
|
size_t content_length = 0;
|
||||||
|
if (ReadIntoBuffer(socket, &control_data_, &content_length)) {
|
||||||
|
size_t peer_id = 0, eoh = 0;
|
||||||
|
bool ok = ParseServerResponse(control_data_, content_length, &peer_id,
|
||||||
|
&eoh);
|
||||||
|
if (ok) {
|
||||||
|
if (my_id_ == -1) {
|
||||||
|
// First response. Let's store our server assigned ID.
|
||||||
|
ASSERT(state_ == SIGNING_IN);
|
||||||
|
my_id_ = peer_id;
|
||||||
|
ASSERT(my_id_ != -1);
|
||||||
|
|
||||||
|
// The body of the response will be a list of already connected peers.
|
||||||
|
if (content_length) {
|
||||||
|
size_t pos = eoh + 4;
|
||||||
|
while (pos < control_data_.size()) {
|
||||||
|
size_t eol = control_data_.find('\n', pos);
|
||||||
|
if (eol == std::string::npos)
|
||||||
|
break;
|
||||||
|
int id = 0;
|
||||||
|
std::string name;
|
||||||
|
bool connected;
|
||||||
|
if (ParseEntry(control_data_.substr(pos, eol - pos), &name, &id,
|
||||||
|
&connected) && id != my_id_) {
|
||||||
|
peers_[id] = name;
|
||||||
|
callback_->OnPeerConnected(id, name);
|
||||||
|
}
|
||||||
|
pos = eol + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ASSERT(is_connected());
|
||||||
|
callback_->OnSignedIn();
|
||||||
|
} else if (state_ == SIGNING_OUT) {
|
||||||
|
Close();
|
||||||
|
callback_->OnDisconnected();
|
||||||
|
} else if (state_ == SIGNING_OUT_WAITING) {
|
||||||
|
SignOut();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
control_data_.clear();
|
||||||
|
|
||||||
|
if (state_ == SIGNING_IN) {
|
||||||
|
ASSERT(hanging_get_.GetState() == talk_base::Socket::CS_CLOSED);
|
||||||
|
state_ = CONNECTED;
|
||||||
|
hanging_get_.Connect(server_address_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnHangingGetRead(talk_base::AsyncSocket* socket) {
|
||||||
|
LOG(INFO) << __FUNCTION__;
|
||||||
|
size_t content_length = 0;
|
||||||
|
if (ReadIntoBuffer(socket, ¬ification_data_, &content_length)) {
|
||||||
|
size_t peer_id = 0, eoh = 0;
|
||||||
|
bool ok = ParseServerResponse(notification_data_, content_length,
|
||||||
|
&peer_id, &eoh);
|
||||||
|
|
||||||
|
if (ok) {
|
||||||
|
// Store the position where the body begins.
|
||||||
|
size_t pos = eoh + 4;
|
||||||
|
|
||||||
|
if (my_id_ == peer_id) {
|
||||||
|
// A notification about a new member or a member that just
|
||||||
|
// disconnected.
|
||||||
|
int id = 0;
|
||||||
|
std::string name;
|
||||||
|
bool connected = false;
|
||||||
|
if (ParseEntry(notification_data_.substr(pos), &name, &id,
|
||||||
|
&connected)) {
|
||||||
|
if (connected) {
|
||||||
|
peers_[id] = name;
|
||||||
|
callback_->OnPeerConnected(id, name);
|
||||||
|
} else {
|
||||||
|
peers_.erase(id);
|
||||||
|
callback_->OnPeerDisconnected(id, name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
callback_->OnMessageFromPeer(peer_id,
|
||||||
|
notification_data_.substr(pos));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
notification_data_.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hanging_get_.GetState() == talk_base::Socket::CS_CLOSED)
|
||||||
|
hanging_get_.Connect(server_address_);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parses a single line entry in the form "<name>,<id>,<connected>"
|
||||||
|
bool ParseEntry(const std::string& entry, std::string* name, int* id,
|
||||||
|
bool* connected) {
|
||||||
|
ASSERT(name);
|
||||||
|
ASSERT(id);
|
||||||
|
ASSERT(connected);
|
||||||
|
ASSERT(entry.length());
|
||||||
|
|
||||||
|
*connected = false;
|
||||||
|
size_t separator = entry.find(',');
|
||||||
|
if (separator != std::string::npos) {
|
||||||
|
*id = atoi(&entry[separator + 1]);
|
||||||
|
name->assign(entry.substr(0, separator));
|
||||||
|
separator = entry.find(',', separator + 1);
|
||||||
|
if (separator != std::string::npos) {
|
||||||
|
*connected = atoi(&entry[separator + 1]) ? true : false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return !name->empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
int GetResponseStatus(const std::string& response) {
|
||||||
|
int status = -1;
|
||||||
|
size_t pos = response.find(' ');
|
||||||
|
if (pos != std::string::npos)
|
||||||
|
status = atoi(&response[pos + 1]);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ParseServerResponse(const std::string& response, size_t content_length,
|
||||||
|
size_t* peer_id, size_t* eoh) {
|
||||||
|
LOG(INFO) << response;
|
||||||
|
|
||||||
|
int status = GetResponseStatus(response.c_str());
|
||||||
|
if (status != 200) {
|
||||||
|
LOG(LS_ERROR) << "Received error from server";
|
||||||
|
Close();
|
||||||
|
callback_->OnDisconnected();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
*eoh = response.find("\r\n\r\n");
|
||||||
|
ASSERT(*eoh != std::string::npos);
|
||||||
|
if (*eoh == std::string::npos)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
*peer_id = -1;
|
||||||
|
|
||||||
|
// See comment in peer_channel.cc for why we use the Pragma header and
|
||||||
|
// not e.g. "X-Peer-Id".
|
||||||
|
GetHeaderValue(response, *eoh, "\r\nPragma: ", peer_id);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnClose(talk_base::AsyncSocket* socket, int err) {
|
||||||
|
LOG(INFO) << __FUNCTION__;
|
||||||
|
socket->Close();
|
||||||
|
if (err != WSAECONNREFUSED) {
|
||||||
|
if (socket == &hanging_get_) {
|
||||||
|
if (state_ == CONNECTED) {
|
||||||
|
LOG(INFO) << "Issuing a new hanging get";
|
||||||
|
hanging_get_.Close();
|
||||||
|
hanging_get_.Connect(server_address_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Failed to connect to the server.
|
||||||
|
Close();
|
||||||
|
callback_->OnDisconnected();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PeerConnectionClientObserver* callback_;
|
||||||
|
talk_base::SocketAddress server_address_;
|
||||||
|
talk_base::Win32Socket control_socket_;
|
||||||
|
talk_base::Win32Socket hanging_get_;
|
||||||
|
std::string onconnect_data_;
|
||||||
|
std::string control_data_;
|
||||||
|
std::string notification_data_;
|
||||||
|
Peers peers_;
|
||||||
|
State state_;
|
||||||
|
int my_id_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ConnectionObserver
|
||||||
|
: public PeerConnectionObserver,
|
||||||
|
public PeerConnectionClientObserver,
|
||||||
|
public MainWndCallback,
|
||||||
|
public talk_base::Win32Window {
|
||||||
|
public:
|
||||||
|
enum WindowMessages {
|
||||||
|
MEDIA_CHANNELS_INITIALIZED = WM_APP + 1,
|
||||||
|
PEER_CONNECTION_CLOSED,
|
||||||
|
SEND_MESSAGE_TO_PEER,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum HandshakeState {
|
||||||
|
NONE,
|
||||||
|
INITIATOR,
|
||||||
|
ANSWER_RECEIVED,
|
||||||
|
OFFER_RECEIVED,
|
||||||
|
QUIT_SENT,
|
||||||
|
};
|
||||||
|
|
||||||
|
ConnectionObserver(PeerConnectionClient* client,
|
||||||
|
MainWnd* main_wnd)
|
||||||
|
: handshake_(NONE),
|
||||||
|
waiting_for_audio_(false),
|
||||||
|
waiting_for_video_(false),
|
||||||
|
peer_id_(-1),
|
||||||
|
video_channel_(-1),
|
||||||
|
audio_channel_(-1),
|
||||||
|
client_(client),
|
||||||
|
main_wnd_(main_wnd) {
|
||||||
|
// Create a window for posting notifications back to from other threads.
|
||||||
|
bool ok = Create(HWND_MESSAGE, L"ConnectionObserver", 0, 0, 0, 0, 0, 0);
|
||||||
|
ASSERT(ok);
|
||||||
|
client_->RegisterObserver(this);
|
||||||
|
main_wnd->RegisterObserver(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
~ConnectionObserver() {
|
||||||
|
ASSERT(peer_connection_.get() == NULL);
|
||||||
|
Destroy();
|
||||||
|
DeletePeerConnection();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool has_video() const {
|
||||||
|
return video_channel_ != -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool has_audio() const {
|
||||||
|
return audio_channel_ != -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool connection_active() const {
|
||||||
|
return peer_connection_.get() != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Close() {
|
||||||
|
if (peer_connection_.get()) {
|
||||||
|
peer_connection_->Close();
|
||||||
|
} else {
|
||||||
|
client_->SignOut();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool InitializePeerConnection() {
|
||||||
|
ASSERT(peer_connection_.get() == NULL);
|
||||||
|
peer_connection_.reset(new PeerConnection(GetPeerConnectionString()));
|
||||||
|
peer_connection_->RegisterObserver(this);
|
||||||
|
if (!peer_connection_->Init()) {
|
||||||
|
DeletePeerConnection();
|
||||||
|
} else {
|
||||||
|
bool audio = peer_connection_->SetAudioDevice("", "", 0);
|
||||||
|
LOG(INFO) << "SetAudioDevice " << (audio ? "succeeded." : "failed.");
|
||||||
|
}
|
||||||
|
return peer_connection_.get() != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeletePeerConnection() {
|
||||||
|
peer_connection_.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void StartCaptureDevice() {
|
||||||
|
ASSERT(peer_connection_.get());
|
||||||
|
if (main_wnd_->IsWindow()) {
|
||||||
|
main_wnd_->SwitchToStreamingUI();
|
||||||
|
|
||||||
|
if (peer_connection_->SetVideoCapture("")) {
|
||||||
|
peer_connection_->SetVideoRenderer(-1, main_wnd_->handle(), 0,
|
||||||
|
0.7f, 0.7f, 0.95f, 0.95f);
|
||||||
|
} else {
|
||||||
|
ASSERT(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// PeerConnectionObserver implementation.
|
||||||
|
//
|
||||||
|
|
||||||
|
virtual void OnError() {
|
||||||
|
LOG(INFO) << __FUNCTION__;
|
||||||
|
ASSERT(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void OnSignalingMessage(const std::string& msg) {
|
||||||
|
LOG(INFO) << __FUNCTION__;
|
||||||
|
|
||||||
|
bool shutting_down = (video_channel_ == -1 && audio_channel_ == -1);
|
||||||
|
|
||||||
|
if (handshake_ == OFFER_RECEIVED && !shutting_down)
|
||||||
|
StartCaptureDevice();
|
||||||
|
|
||||||
|
// Send our answer/offer/shutting down message.
|
||||||
|
// If we're the initiator, this will be our offer. If we just received
|
||||||
|
// an offer, this will be an answer. If PeerConnection::Close has been
|
||||||
|
// called, then this is our signal to the other end that we're shutting
|
||||||
|
// down.
|
||||||
|
if (handshake_ != QUIT_SENT) {
|
||||||
|
SendMessage(handle(), SEND_MESSAGE_TO_PEER, 0,
|
||||||
|
reinterpret_cast<LPARAM>(&msg));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shutting_down) {
|
||||||
|
handshake_ = QUIT_SENT;
|
||||||
|
PostMessage(handle(), PEER_CONNECTION_CLOSED, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Called when a remote stream is added
|
||||||
|
virtual void OnAddStream(const std::string& stream_id, int channel_id,
|
||||||
|
bool video) {
|
||||||
|
LOG(INFO) << __FUNCTION__ << " " << stream_id;
|
||||||
|
bool send_notification = (waiting_for_video_ || waiting_for_audio_);
|
||||||
|
if (video) {
|
||||||
|
ASSERT(video_channel_ == -1);
|
||||||
|
video_channel_ = channel_id;
|
||||||
|
waiting_for_video_ = false;
|
||||||
|
LOG(INFO) << "Setting video renderer for channel: " << channel_id;
|
||||||
|
bool ok = peer_connection_->SetVideoRenderer(channel_id,
|
||||||
|
main_wnd_->handle(), 1, 0.0f, 0.0f, 1.0f, 1.0f);
|
||||||
|
ASSERT(ok);
|
||||||
|
} else {
|
||||||
|
ASSERT(audio_channel_ == -1);
|
||||||
|
audio_channel_ = channel_id;
|
||||||
|
waiting_for_audio_ = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (send_notification && !waiting_for_audio_ && !waiting_for_video_)
|
||||||
|
PostMessage(handle(), MEDIA_CHANNELS_INITIALIZED, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void OnRemoveStream(const std::string& stream_id,
|
||||||
|
int channel_id,
|
||||||
|
bool video) {
|
||||||
|
LOG(INFO) << __FUNCTION__;
|
||||||
|
if (video) {
|
||||||
|
ASSERT(channel_id == video_channel_);
|
||||||
|
video_channel_ = -1;
|
||||||
|
} else {
|
||||||
|
ASSERT(channel_id == audio_channel_);
|
||||||
|
audio_channel_ = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// PeerConnectionClientObserver implementation.
|
||||||
|
//
|
||||||
|
|
||||||
|
virtual void OnSignedIn() {
|
||||||
|
LOG(INFO) << __FUNCTION__;
|
||||||
|
main_wnd_->SwitchToPeerList(client_->peers());
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void OnDisconnected() {
|
||||||
|
LOG(INFO) << __FUNCTION__;
|
||||||
|
if (peer_connection_.get()) {
|
||||||
|
peer_connection_->Close();
|
||||||
|
} else if (main_wnd_->IsWindow()) {
|
||||||
|
main_wnd_->SwitchToConnectUI();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void OnPeerConnected(int id, const std::string& name) {
|
||||||
|
LOG(INFO) << __FUNCTION__;
|
||||||
|
// Refresh the list if we're showing it.
|
||||||
|
if (main_wnd_->current_ui() == MainWnd::LIST_PEERS)
|
||||||
|
main_wnd_->SwitchToPeerList(client_->peers());
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void OnPeerDisconnected(int id, const std::string& name) {
|
||||||
|
LOG(INFO) << __FUNCTION__;
|
||||||
|
if (id == peer_id_) {
|
||||||
|
LOG(INFO) << "Our peer disconnected";
|
||||||
|
peer_id_ = -1;
|
||||||
|
// TODO: Somehow make sure that Close has been called?
|
||||||
|
if (peer_connection_.get())
|
||||||
|
peer_connection_->Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Refresh the list if we're showing it.
|
||||||
|
if (main_wnd_->current_ui() == MainWnd::LIST_PEERS)
|
||||||
|
main_wnd_->SwitchToPeerList(client_->peers());
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void OnMessageFromPeer(int peer_id, const std::string& message) {
|
||||||
|
ASSERT(peer_id_ == peer_id || peer_id_ == -1);
|
||||||
|
|
||||||
|
if (handshake_ == NONE) {
|
||||||
|
handshake_ = OFFER_RECEIVED;
|
||||||
|
peer_id_ = peer_id;
|
||||||
|
if (!peer_connection_.get()) {
|
||||||
|
// Got an offer. Give it to the PeerConnection instance.
|
||||||
|
// Once processed, we will get a callback to OnSignalingMessage with
|
||||||
|
// our 'answer' which we'll send to the peer.
|
||||||
|
LOG(INFO) << "Got an offer from our peer: " << peer_id;
|
||||||
|
if (!InitializePeerConnection()) {
|
||||||
|
LOG(LS_ERROR) << "Failed to initialize our PeerConnection instance";
|
||||||
|
client_->SignOut();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (handshake_ == INITIATOR) {
|
||||||
|
LOG(INFO) << "Remote peer sent us an answer";
|
||||||
|
handshake_ = ANSWER_RECEIVED;
|
||||||
|
} else {
|
||||||
|
LOG(INFO) << "Remote peer is disconnecting";
|
||||||
|
handshake_ = QUIT_SENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
peer_connection_->SignalingMessage(message);
|
||||||
|
|
||||||
|
if (handshake_ == QUIT_SENT) {
|
||||||
|
DisconnectFromCurrentPeer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// MainWndCallback implementation.
|
||||||
|
//
|
||||||
|
virtual void StartLogin(const std::string& server, int port) {
|
||||||
|
ASSERT(!client_->is_connected());
|
||||||
|
if (!client_->Connect(server, port, GetPeerName())) {
|
||||||
|
MessageBoxA(main_wnd_->handle(),
|
||||||
|
("Failed to connect to " + server).c_str(),
|
||||||
|
"Error", MB_OK | MB_ICONERROR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void DisconnectFromServer() {
|
||||||
|
if (!client_->is_connected())
|
||||||
|
return;
|
||||||
|
client_->SignOut();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void ConnectToPeer(int peer_id) {
|
||||||
|
ASSERT(peer_id_ == -1);
|
||||||
|
ASSERT(peer_id != -1);
|
||||||
|
ASSERT(handshake_ == NONE);
|
||||||
|
|
||||||
|
if (handshake_ != NONE)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (InitializePeerConnection()) {
|
||||||
|
peer_id_ = peer_id;
|
||||||
|
waiting_for_video_ = peer_connection_->AddStream(kVideoLabel, true);
|
||||||
|
waiting_for_audio_ = peer_connection_->AddStream(kAudioLabel, false);
|
||||||
|
if (waiting_for_video_ || waiting_for_audio_)
|
||||||
|
handshake_ = INITIATOR;
|
||||||
|
ASSERT(waiting_for_video_ || waiting_for_audio_);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (handshake_ == NONE) {
|
||||||
|
::MessageBoxA(main_wnd_->handle(), "Failed to initialize PeerConnection",
|
||||||
|
"Error", MB_OK | MB_ICONERROR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void DisconnectFromCurrentPeer() {
|
||||||
|
if (peer_connection_.get())
|
||||||
|
peer_connection_->Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Win32Window implementation.
|
||||||
|
//
|
||||||
|
|
||||||
|
virtual bool OnMessage(UINT msg, WPARAM wp, LPARAM lp, LRESULT& result) {
|
||||||
|
bool ret = true;
|
||||||
|
if (msg == MEDIA_CHANNELS_INITIALIZED) {
|
||||||
|
ASSERT(handshake_ == INITIATOR);
|
||||||
|
bool ok = peer_connection_->Connect();
|
||||||
|
ASSERT(ok);
|
||||||
|
StartCaptureDevice();
|
||||||
|
// When we get an OnSignalingMessage notification, we'll send our
|
||||||
|
// json encoded signaling message to the peer, which is the first step
|
||||||
|
// of establishing a connection.
|
||||||
|
} else if (msg == PEER_CONNECTION_CLOSED) {
|
||||||
|
LOG(INFO) << "PEER_CONNECTION_CLOSED";
|
||||||
|
DeletePeerConnection();
|
||||||
|
::InvalidateRect(main_wnd_->handle(), NULL, TRUE);
|
||||||
|
handshake_ = NONE;
|
||||||
|
waiting_for_audio_ = false;
|
||||||
|
waiting_for_video_ = false;
|
||||||
|
peer_id_ = -1;
|
||||||
|
ASSERT(video_channel_ == -1);
|
||||||
|
ASSERT(audio_channel_ == -1);
|
||||||
|
if (main_wnd_->IsWindow()) {
|
||||||
|
if (client_->is_connected()) {
|
||||||
|
main_wnd_->SwitchToPeerList(client_->peers());
|
||||||
|
} else {
|
||||||
|
main_wnd_->SwitchToConnectUI();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
DisconnectFromServer();
|
||||||
|
}
|
||||||
|
} else if (msg == SEND_MESSAGE_TO_PEER) {
|
||||||
|
client_->SendToPeer(peer_id_, *reinterpret_cast<std::string*>(lp));
|
||||||
|
} else {
|
||||||
|
ret = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
HandshakeState handshake_;
|
||||||
|
bool waiting_for_audio_;
|
||||||
|
bool waiting_for_video_;
|
||||||
|
int peer_id_;
|
||||||
|
scoped_ptr<PeerConnection> peer_connection_;
|
||||||
|
PeerConnectionClient* client_;
|
||||||
|
MainWnd* main_wnd_;
|
||||||
|
int video_channel_;
|
||||||
|
int audio_channel_;
|
||||||
|
};
|
||||||
|
|
||||||
|
int PASCAL wWinMain(HINSTANCE instance, HINSTANCE prev_instance,
|
||||||
|
wchar_t* cmd_line, int cmd_show) {
|
||||||
|
talk_base::EnsureWinsockInit();
|
||||||
|
|
||||||
|
webrtc::Trace::CreateTrace();
|
||||||
|
webrtc::Trace::SetTraceFile("session_test_trace.txt");
|
||||||
|
webrtc::Trace::SetLevelFilter(webrtc::kTraceWarning);
|
||||||
|
|
||||||
|
MainWnd wnd;
|
||||||
|
if (!wnd.Create()) {
|
||||||
|
ASSERT(false);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
PeerConnectionClient client;
|
||||||
|
ConnectionObserver observer(&client, &wnd);
|
||||||
|
|
||||||
|
// Main loop.
|
||||||
|
MSG msg;
|
||||||
|
BOOL gm;
|
||||||
|
while ((gm = ::GetMessage(&msg, NULL, 0, 0)) && gm != -1) {
|
||||||
|
if (!wnd.PreTranslateMessage(&msg)) {
|
||||||
|
::TranslateMessage(&msg);
|
||||||
|
::DispatchMessage(&msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (observer.connection_active() || client.is_connected()) {
|
||||||
|
observer.Close();
|
||||||
|
while ((observer.connection_active() || client.is_connected()) &&
|
||||||
|
(gm = ::GetMessage(&msg, NULL, 0, 0)) && gm != -1) {
|
||||||
|
::TranslateMessage(&msg);
|
||||||
|
::DispatchMessage(&msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
120
third_party_mods/libjingle/source/talk/app/videoengine.h
Normal file
120
third_party_mods/libjingle/source/talk/app/videoengine.h
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
/*
|
||||||
|
* libjingle
|
||||||
|
* Copyright 2004--2011, Google Inc.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
* 3. The name of the author may not be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||||
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||||
|
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||||
|
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||||
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||||
|
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||||
|
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef TALK_APP_WEBRTC_VIDEOENGINE_H_
|
||||||
|
#define TALK_APP_WEBRTC_VIDEOENGINE_H_
|
||||||
|
|
||||||
|
#include "talk/base/common.h"
|
||||||
|
#include "common_types.h"
|
||||||
|
#include "video_engine/main/interface/vie_base.h"
|
||||||
|
#include "video_engine/main/interface/vie_capture.h"
|
||||||
|
#include "video_engine/main/interface/vie_codec.h"
|
||||||
|
#include "video_engine/main/interface/vie_errors.h"
|
||||||
|
#include "video_engine/main/interface/vie_image_process.h"
|
||||||
|
#include "video_engine/main/interface/vie_network.h"
|
||||||
|
#include "video_engine/main/interface/vie_render.h"
|
||||||
|
#include "video_engine/main/interface/vie_rtp_rtcp.h"
|
||||||
|
|
||||||
|
namespace webrtc {
|
||||||
|
|
||||||
|
// all tracing macros should go to a common file
|
||||||
|
|
||||||
|
// automatically handles lifetime of VideoEngine
|
||||||
|
class scoped_video_engine {
|
||||||
|
public:
|
||||||
|
explicit scoped_video_engine(VideoEngine* e) : ptr(e) {}
|
||||||
|
// VERIFY, to ensure that there are no leaks at shutdown
|
||||||
|
~scoped_video_engine() {
|
||||||
|
if (ptr) {
|
||||||
|
VideoEngine::Delete(ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
VideoEngine* get() const { return ptr; }
|
||||||
|
private:
|
||||||
|
VideoEngine* ptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
// scoped_ptr class to handle obtaining and releasing VideoEngine
|
||||||
|
// interface pointers
|
||||||
|
template<class T> class scoped_video_ptr {
|
||||||
|
public:
|
||||||
|
explicit scoped_video_ptr(const scoped_video_engine& e)
|
||||||
|
: ptr(T::GetInterface(e.get())) {}
|
||||||
|
explicit scoped_video_ptr(T* p) : ptr(p) {}
|
||||||
|
~scoped_video_ptr() { if (ptr) ptr->Release(); }
|
||||||
|
T* operator->() const { return ptr; }
|
||||||
|
T* get() const { return ptr; }
|
||||||
|
private:
|
||||||
|
T* ptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Utility class for aggregating the various WebRTC interface.
|
||||||
|
// Fake implementations can also be injected for testing.
|
||||||
|
class VideoEngineWrapper {
|
||||||
|
public:
|
||||||
|
VideoEngineWrapper()
|
||||||
|
: engine_(VideoEngine::Create()),
|
||||||
|
base_(engine_), codec_(engine_), capture_(engine_),
|
||||||
|
network_(engine_), render_(engine_), rtp_(engine_),
|
||||||
|
image_(engine_) {
|
||||||
|
}
|
||||||
|
|
||||||
|
VideoEngineWrapper(ViEBase* base, ViECodec* codec, ViECapture* capture,
|
||||||
|
ViENetwork* network, ViERender* render,
|
||||||
|
ViERTP_RTCP* rtp, ViEImageProcess* image)
|
||||||
|
: engine_(NULL),
|
||||||
|
base_(base), codec_(codec), capture_(capture),
|
||||||
|
network_(network), render_(render), rtp_(rtp),
|
||||||
|
image_(image) {
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~VideoEngineWrapper() {}
|
||||||
|
VideoEngine* engine() { return engine_.get(); }
|
||||||
|
ViEBase* base() { return base_.get(); }
|
||||||
|
ViECodec* codec() { return codec_.get(); }
|
||||||
|
ViECapture* capture() { return capture_.get(); }
|
||||||
|
ViENetwork* network() { return network_.get(); }
|
||||||
|
ViERender* render() { return render_.get(); }
|
||||||
|
ViERTP_RTCP* rtp() { return rtp_.get(); }
|
||||||
|
ViEImageProcess* sync() { return image_.get(); }
|
||||||
|
int error() { return base_->LastError(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
scoped_video_engine engine_;
|
||||||
|
scoped_video_ptr<ViEBase> base_;
|
||||||
|
scoped_video_ptr<ViECodec> codec_;
|
||||||
|
scoped_video_ptr<ViECapture> capture_;
|
||||||
|
scoped_video_ptr<ViENetwork> network_;
|
||||||
|
scoped_video_ptr<ViERender> render_;
|
||||||
|
scoped_video_ptr<ViERTP_RTCP> rtp_;
|
||||||
|
scoped_video_ptr<ViEImageProcess> image_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} //namespace webrtc
|
||||||
|
|
||||||
|
#endif // TALK_APP_WEBRTC_VOICEENGINE_H_
|
||||||
756
third_party_mods/libjingle/source/talk/app/videomediaengine.cc
Normal file
756
third_party_mods/libjingle/source/talk/app/videomediaengine.cc
Normal file
@ -0,0 +1,756 @@
|
|||||||
|
|
||||||
|
|
||||||
|
#include "talk/app/videomediaengine.h"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#ifdef PLATFORM_CHROMIUM
|
||||||
|
#include "content/renderer/video_capture_chrome.h"
|
||||||
|
#endif
|
||||||
|
#include "talk/base/buffer.h"
|
||||||
|
#include "talk/base/byteorder.h"
|
||||||
|
#include "talk/base/logging.h"
|
||||||
|
#include "talk/base/stringutils.h"
|
||||||
|
#include "talk/app/voicemediaengine.h"
|
||||||
|
|
||||||
|
#include "modules/video_capture/main/interface/video_capture.h"
|
||||||
|
|
||||||
|
#ifndef ARRAYSIZE
|
||||||
|
#define ARRAYSIZE(a) (sizeof(a) / sizeof((a)[0]))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace webrtc {
|
||||||
|
|
||||||
|
static const int kDefaultLogSeverity = 3;
|
||||||
|
static const int kStartVideoBitrate = 300;
|
||||||
|
static const int kMaxVideoBitrate = 1000;
|
||||||
|
|
||||||
|
const RtcVideoEngine::VideoCodecPref RtcVideoEngine::kVideoCodecPrefs[] = {
|
||||||
|
{"VP8", 104, 0},
|
||||||
|
{"H264", 105, 1}
|
||||||
|
};
|
||||||
|
|
||||||
|
RtcVideoEngine::RtcVideoEngine()
|
||||||
|
: video_engine_(new VideoEngineWrapper()),
|
||||||
|
capture_(NULL),
|
||||||
|
capture_id_(-1),
|
||||||
|
voice_engine_(NULL),
|
||||||
|
initialized_(false),
|
||||||
|
log_level_(kDefaultLogSeverity),
|
||||||
|
capture_started_(false){
|
||||||
|
}
|
||||||
|
|
||||||
|
RtcVideoEngine::RtcVideoEngine(RtcVoiceEngine* voice_engine)
|
||||||
|
: video_engine_(new VideoEngineWrapper()),
|
||||||
|
capture_(NULL),
|
||||||
|
capture_id_(-1),
|
||||||
|
voice_engine_(voice_engine),
|
||||||
|
initialized_(false),
|
||||||
|
log_level_(kDefaultLogSeverity),
|
||||||
|
capture_started_(false){
|
||||||
|
}
|
||||||
|
|
||||||
|
RtcVideoEngine::~RtcVideoEngine() {
|
||||||
|
LOG(LS_VERBOSE) << " RtcVideoEngine::~RtcVideoEngine";
|
||||||
|
video_engine_->engine()->SetTraceCallback(NULL);
|
||||||
|
Terminate();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RtcVideoEngine::Init() {
|
||||||
|
LOG(LS_VERBOSE) << "RtcVideoEngine::Init";
|
||||||
|
ApplyLogging();
|
||||||
|
if (video_engine_->engine()->SetTraceCallback(this) != 0) {
|
||||||
|
LOG(LS_ERROR) << "SetTraceCallback error";
|
||||||
|
}
|
||||||
|
|
||||||
|
bool result = InitVideoEngine(voice_engine_);
|
||||||
|
if (result) {
|
||||||
|
LOG(LS_INFO) << "VideoEngine Init done";
|
||||||
|
} else {
|
||||||
|
LOG(LS_ERROR) << "VideoEngine Init failed, releasing";
|
||||||
|
Terminate();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RtcVideoEngine::InitVideoEngine(RtcVoiceEngine* voice_engine) {
|
||||||
|
LOG(LS_VERBOSE) << "RtcVideoEngine::InitVideoEngine";
|
||||||
|
|
||||||
|
bool ret = true;
|
||||||
|
if (video_engine_->base()->Init() != 0) {
|
||||||
|
LOG(LS_ERROR) << "VideoEngine Init method failed";
|
||||||
|
ret = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!voice_engine) {
|
||||||
|
LOG(LS_WARNING) << "NULL voice engine";
|
||||||
|
} else if ((video_engine_->base()->SetVoiceEngine(
|
||||||
|
voice_engine->webrtc()->engine())) != 0) {
|
||||||
|
LOG(LS_WARNING) << "Failed to SetVoiceEngine";
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((video_engine_->base()->RegisterObserver(*this)) != 0) {
|
||||||
|
LOG(LS_WARNING) << "Failed to register observer";
|
||||||
|
}
|
||||||
|
|
||||||
|
int ncodecs = video_engine_->codec()->NumberOfCodecs();
|
||||||
|
for (int i = 0; i < ncodecs - 2; ++i) {
|
||||||
|
VideoCodec wcodec;
|
||||||
|
if ((video_engine_->codec()->GetCodec(i, wcodec) == 0) &&
|
||||||
|
(strncmp(wcodec.plName, "I420", 4) != 0)) { //ignore I420
|
||||||
|
cricket::VideoCodec codec(wcodec.plType, wcodec.plName, wcodec.width,
|
||||||
|
wcodec.height, wcodec.maxFramerate, i);
|
||||||
|
LOG(LS_INFO) << codec.ToString();
|
||||||
|
video_codecs_.push_back(codec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::sort(video_codecs_.begin(), video_codecs_.end(),
|
||||||
|
&cricket::VideoCodec::Preferable);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RtcVideoEngine::PerformanceAlarm(const unsigned int cpuLoad) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RtcVideoEngine::Print(const TraceLevel level, const char *traceString,
|
||||||
|
const int length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int RtcVideoEngine::GetCodecPreference(const char* name) {
|
||||||
|
for (size_t i = 0; i < ARRAY_SIZE(kVideoCodecPrefs); ++i) {
|
||||||
|
if (strcmp(kVideoCodecPrefs[i].payload_name, name) == 0) {
|
||||||
|
return kVideoCodecPrefs[i].pref;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RtcVideoEngine::ApplyLogging() {
|
||||||
|
int filter = 0;
|
||||||
|
switch(log_level_) {
|
||||||
|
case talk_base::LS_VERBOSE: filter |= kTraceAll;
|
||||||
|
case talk_base::LS_INFO: filter |= kTraceStateInfo;
|
||||||
|
case talk_base::LS_WARNING: filter |= kTraceWarning;
|
||||||
|
case talk_base::LS_ERROR: filter |= kTraceError | kTraceCritical;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RtcVideoEngine::Terminate() {
|
||||||
|
LOG(LS_INFO) << "RtcVideoEngine::Terminate";
|
||||||
|
ReleaseCaptureDevice();
|
||||||
|
}
|
||||||
|
|
||||||
|
int RtcVideoEngine::GetCapabilities() {
|
||||||
|
return cricket::MediaEngine::VIDEO_RECV | cricket::MediaEngine::VIDEO_SEND;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RtcVideoEngine::SetOptions(int options) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RtcVideoEngine::ReleaseCaptureDevice() {
|
||||||
|
if (capture_) {
|
||||||
|
// Stop capture
|
||||||
|
SetCapture(false);
|
||||||
|
// DisconnectCaptureDevice
|
||||||
|
RtcVideoMediaChannel* channel;
|
||||||
|
for (VideoChannels::const_iterator it = channels_.begin();
|
||||||
|
it != channels_.end(); ++it) {
|
||||||
|
ASSERT(*it != NULL);
|
||||||
|
channel = *it;
|
||||||
|
video_engine_->capture()->DisconnectCaptureDevice(channel->video_channel());
|
||||||
|
}
|
||||||
|
// ReleaseCaptureDevice
|
||||||
|
video_engine_->capture()->ReleaseCaptureDevice(capture_id_);
|
||||||
|
capture_id_ = -1;
|
||||||
|
#ifdef PLATFORM_CHROMIUM
|
||||||
|
VideoCaptureChrome::DestroyVideoCapture(
|
||||||
|
static_cast<VideoCaptureChrome*>(capture_));
|
||||||
|
#else
|
||||||
|
webrtc::VideoCaptureModule::Destroy(capture_);
|
||||||
|
#endif
|
||||||
|
capture_ = NULL;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RtcVideoEngine::SetCaptureDevice(const cricket::Device* cam) {
|
||||||
|
ASSERT(video_engine_.get());
|
||||||
|
ASSERT(cam != NULL);
|
||||||
|
|
||||||
|
ReleaseCaptureDevice();
|
||||||
|
|
||||||
|
#ifdef PLATFORM_CHROMIUM
|
||||||
|
int cam_id = atol(cam->id.c_str());
|
||||||
|
if (cam_id == -1)
|
||||||
|
return false;
|
||||||
|
unsigned char uniqueId[16];
|
||||||
|
capture_ = VideoCaptureChrome::CreateVideoCapture(cam_id, uniqueId);
|
||||||
|
#else
|
||||||
|
WebRtc_UWord8 device_name[128];
|
||||||
|
WebRtc_UWord8 device_id[260];
|
||||||
|
VideoCaptureModule::DeviceInfo* device_info =
|
||||||
|
VideoCaptureModule::CreateDeviceInfo(0);
|
||||||
|
for (WebRtc_UWord32 i = 0; i < device_info->NumberOfDevices(); ++i) {
|
||||||
|
if (device_info->GetDeviceName(i, device_name, ARRAYSIZE(device_name),
|
||||||
|
device_id, ARRAYSIZE(device_id)) == 0) {
|
||||||
|
if ((cam->name.compare("") == 0) ||
|
||||||
|
(cam->id.compare((char*) device_id) == 0)) {
|
||||||
|
capture_ = VideoCaptureModule::Create(1234, device_id);
|
||||||
|
if (capture_) {
|
||||||
|
LOG(INFO) << "Found video capture device: " << device_name;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
VideoCaptureModule::DestroyDeviceInfo(device_info);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (!capture_)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
ViECapture* vie_capture = video_engine_->capture();
|
||||||
|
if (vie_capture->AllocateCaptureDevice(*capture_, capture_id_) == 0) {
|
||||||
|
// Connect to all the channels
|
||||||
|
RtcVideoMediaChannel* channel;
|
||||||
|
for (VideoChannels::const_iterator it = channels_.begin();
|
||||||
|
it != channels_.end(); ++it) {
|
||||||
|
ASSERT(*it != NULL);
|
||||||
|
channel = *it;
|
||||||
|
vie_capture->ConnectCaptureDevice(capture_id_, channel->video_channel());
|
||||||
|
}
|
||||||
|
SetCapture(true);
|
||||||
|
} else {
|
||||||
|
ASSERT(capture_id_ == -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (capture_id_ != -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RtcVideoEngine::SetVideoRenderer(int channel_id,
|
||||||
|
void* window,
|
||||||
|
unsigned int zOrder,
|
||||||
|
float left,
|
||||||
|
float top,
|
||||||
|
float right,
|
||||||
|
float bottom) {
|
||||||
|
int ret;
|
||||||
|
if (channel_id == -1)
|
||||||
|
channel_id = capture_id_;
|
||||||
|
ret = video_engine_->render()->AddRenderer(
|
||||||
|
channel_id, window, zOrder, left, top, right, bottom);
|
||||||
|
if (ret !=0 )
|
||||||
|
return false;
|
||||||
|
ret = video_engine_->render()->StartRender(channel_id);
|
||||||
|
if (ret !=0 )
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RtcVideoEngine::SetLocalRenderer(cricket::VideoRenderer* renderer) {
|
||||||
|
LOG(LS_WARNING) << "Not required call SetLocalRenderer for webrtc";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
cricket::CaptureResult RtcVideoEngine::SetCapture(bool capture) {
|
||||||
|
if (capture_started_ == capture)
|
||||||
|
return cricket::CR_SUCCESS;
|
||||||
|
|
||||||
|
if (capture_id_ != -1) {
|
||||||
|
int ret;
|
||||||
|
if (capture)
|
||||||
|
ret = video_engine_->capture()->StartCapture(capture_id_);
|
||||||
|
else
|
||||||
|
ret = video_engine_->capture()->StopCapture(capture_id_);
|
||||||
|
if (ret == 0) {
|
||||||
|
capture_started_ = capture;
|
||||||
|
return cricket::CR_SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return cricket::CR_NO_DEVICE;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<cricket::VideoCodec>& RtcVideoEngine::codecs() const {
|
||||||
|
return video_codecs_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RtcVideoEngine::SetLogging(int min_sev, const char* filter) {
|
||||||
|
log_level_ = min_sev;
|
||||||
|
ApplyLogging();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RtcVideoEngine::SetDefaultEncoderConfig(
|
||||||
|
const cricket::VideoEncoderConfig& config) {
|
||||||
|
bool ret = SetDefaultCodec(config.max_codec);
|
||||||
|
if (ret) {
|
||||||
|
default_encoder_config_ = config;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RtcVideoEngine::SetDefaultCodec(const cricket::VideoCodec& codec) {
|
||||||
|
default_codec_ = codec;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
RtcVideoMediaChannel* RtcVideoEngine::CreateChannel(
|
||||||
|
cricket::VoiceMediaChannel* voice_channel) {
|
||||||
|
RtcVideoMediaChannel* channel =
|
||||||
|
new RtcVideoMediaChannel(this, voice_channel);
|
||||||
|
if (channel) {
|
||||||
|
if (!channel->Init()) {
|
||||||
|
delete channel;
|
||||||
|
channel = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return channel;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RtcVideoEngine::FindCodec(const cricket::VideoCodec& codec) {
|
||||||
|
for (size_t i = 0; i < video_codecs_.size(); ++i) {
|
||||||
|
if (video_codecs_[i].Matches(codec)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RtcVideoEngine::ConvertToCricketVideoCodec(
|
||||||
|
const VideoCodec& in_codec, cricket::VideoCodec& out_codec) {
|
||||||
|
out_codec.id = in_codec.plType;
|
||||||
|
out_codec.name = in_codec.plName;
|
||||||
|
out_codec.width = in_codec.width;
|
||||||
|
out_codec.height = in_codec.height;
|
||||||
|
out_codec.framerate = in_codec.maxFramerate;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RtcVideoEngine::ConvertFromCricketVideoCodec(
|
||||||
|
const cricket::VideoCodec& in_codec, VideoCodec& out_codec) {
|
||||||
|
out_codec.plType = in_codec.id;
|
||||||
|
strcpy(out_codec.plName, in_codec.name.c_str());
|
||||||
|
out_codec.width = 352; //in_codec.width;
|
||||||
|
out_codec.height = 288; //in_codec.height;
|
||||||
|
out_codec.maxFramerate = 30; //in_codec.framerate;
|
||||||
|
|
||||||
|
if (strncmp(out_codec.plName, "VP8", 3) == 0) {
|
||||||
|
out_codec.codecType = kVideoCodecVP8;
|
||||||
|
} else if (strncmp(out_codec.plName, "H263", 4) == 0) {
|
||||||
|
out_codec.codecType = kVideoCodecH263;
|
||||||
|
} else if (strncmp(out_codec.plName, "H264", 4) == 0) {
|
||||||
|
out_codec.codecType = kVideoCodecH264;
|
||||||
|
} else if (strncmp(out_codec.plName, "I420", 4) == 0) {
|
||||||
|
out_codec.codecType = kVideoCodecI420;
|
||||||
|
} else {
|
||||||
|
LOG(LS_INFO) << "invalid codec type";
|
||||||
|
}
|
||||||
|
|
||||||
|
out_codec.maxBitrate = kMaxVideoBitrate;
|
||||||
|
out_codec.startBitrate = kStartVideoBitrate;
|
||||||
|
out_codec.minBitrate = kStartVideoBitrate;
|
||||||
|
}
|
||||||
|
|
||||||
|
int RtcVideoEngine::GetLastVideoEngineError() {
|
||||||
|
return video_engine_->base()->LastError();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RtcVideoEngine::RegisterChannel(RtcVideoMediaChannel *channel) {
|
||||||
|
talk_base::CritScope lock(&channels_cs_);
|
||||||
|
channels_.push_back(channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RtcVideoEngine::UnregisterChannel(RtcVideoMediaChannel *channel) {
|
||||||
|
talk_base::CritScope lock(&channels_cs_);
|
||||||
|
VideoChannels::iterator i = std::find(channels_.begin(),
|
||||||
|
channels_.end(),
|
||||||
|
channel);
|
||||||
|
if (i != channels_.end()) {
|
||||||
|
channels_.erase(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// RtcVideoMediaChannel
|
||||||
|
|
||||||
|
RtcVideoMediaChannel::RtcVideoMediaChannel(
|
||||||
|
RtcVideoEngine* engine, cricket::VoiceMediaChannel* channel)
|
||||||
|
: engine_(engine),
|
||||||
|
voice_channel_(channel),
|
||||||
|
video_channel_(-1),
|
||||||
|
sending_(false),
|
||||||
|
render_started_(false) {
|
||||||
|
engine->RegisterChannel(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RtcVideoMediaChannel::Init() {
|
||||||
|
bool ret = true;
|
||||||
|
if (engine_->video_engine()->base()->CreateChannel(video_channel_) != 0) {
|
||||||
|
LOG(LS_ERROR) << "ViE CreateChannel Failed!!";
|
||||||
|
ret = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG(LS_INFO) << "RtcVideoMediaChannel::Init "
|
||||||
|
<< "video_channel " << video_channel_ << " created";
|
||||||
|
//connect audio channel
|
||||||
|
if (voice_channel_) {
|
||||||
|
RtcVoiceMediaChannel* channel =
|
||||||
|
static_cast<RtcVoiceMediaChannel*> (voice_channel_);
|
||||||
|
if (engine_->video_engine()->base()->ConnectAudioChannel(
|
||||||
|
video_channel_, channel->audio_channel()) != 0) {
|
||||||
|
LOG(LS_WARNING) << "ViE ConnectAudioChannel failed"
|
||||||
|
<< "A/V not synchronized";
|
||||||
|
// Don't set ret to false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Register external transport
|
||||||
|
if (engine_->video_engine()->network()->RegisterSendTransport(
|
||||||
|
video_channel_, *this) != 0) {
|
||||||
|
ret = false;
|
||||||
|
} else {
|
||||||
|
EnableRtcp();
|
||||||
|
EnablePLI();
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
RtcVideoMediaChannel::~RtcVideoMediaChannel() {
|
||||||
|
// Stop and remote renderer
|
||||||
|
SetRender(false);
|
||||||
|
if (engine()->video_engine()->render()->RemoveRenderer(video_channel_) == -1) {
|
||||||
|
LOG(LS_ERROR) << "Video RemoveRenderer failed for channel "
|
||||||
|
<< video_channel_;
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeRegister external transport
|
||||||
|
if (engine()->video_engine()->network()->DeregisterSendTransport(
|
||||||
|
video_channel_) == -1) {
|
||||||
|
LOG(LS_ERROR) << "DeRegisterSendTransport failed for channel id "
|
||||||
|
<< video_channel_;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unregister RtcChannel with the engine.
|
||||||
|
engine()->UnregisterChannel(this);
|
||||||
|
|
||||||
|
// Delete VideoChannel
|
||||||
|
if (engine()->video_engine()->base()->DeleteChannel(video_channel_) == -1) {
|
||||||
|
LOG(LS_ERROR) << "Video DeleteChannel failed for channel "
|
||||||
|
<< video_channel_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RtcVideoMediaChannel::SetRecvCodecs(
|
||||||
|
const std::vector<cricket::VideoCodec>& codecs) {
|
||||||
|
bool ret = true;
|
||||||
|
for (std::vector<cricket::VideoCodec>::const_iterator iter = codecs.begin();
|
||||||
|
iter != codecs.end(); ++iter) {
|
||||||
|
if (engine()->FindCodec(*iter)) {
|
||||||
|
VideoCodec wcodec;
|
||||||
|
engine()->ConvertFromCricketVideoCodec(*iter, wcodec);
|
||||||
|
if (engine()->video_engine()->codec()->SetReceiveCodec(
|
||||||
|
video_channel_, wcodec) != 0) {
|
||||||
|
LOG(LS_ERROR) << "ViE SetReceiveCodec failed"
|
||||||
|
<< " VideoChannel : " << video_channel_ << " Error: "
|
||||||
|
<< engine()->video_engine()->base()->LastError()
|
||||||
|
<< "wcodec " << wcodec.plName;
|
||||||
|
ret = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LOG(LS_INFO) << "Unknown codec" << iter->name;
|
||||||
|
ret = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// make channel ready to receive packets
|
||||||
|
if (ret) {
|
||||||
|
if (engine()->video_engine()->base()->StartReceive(video_channel_) != 0) {
|
||||||
|
LOG(LS_ERROR) << "ViE StartReceive failure";
|
||||||
|
ret = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RtcVideoMediaChannel::SetSendCodecs(
|
||||||
|
const std::vector<cricket::VideoCodec>& codecs) {
|
||||||
|
if (sending_) {
|
||||||
|
LOG(LS_ERROR) << "channel is alredy sending";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//match with local video codec list
|
||||||
|
std::vector<VideoCodec> send_codecs;
|
||||||
|
for (std::vector<cricket::VideoCodec>::const_iterator iter = codecs.begin();
|
||||||
|
iter != codecs.end(); ++iter) {
|
||||||
|
if (engine()->FindCodec(*iter)) {
|
||||||
|
VideoCodec wcodec;
|
||||||
|
engine()->ConvertFromCricketVideoCodec(*iter, wcodec);
|
||||||
|
send_codecs.push_back(wcodec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if none matches, return with set
|
||||||
|
if (send_codecs.empty()) {
|
||||||
|
LOG(LS_ERROR) << "No matching codecs avilable";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//select the first matched codec
|
||||||
|
const VideoCodec& codec(send_codecs[0]);
|
||||||
|
send_codec_ = codec;
|
||||||
|
if (engine()->video_engine()->codec()->SetSendCodec(
|
||||||
|
video_channel_, codec) != 0) {
|
||||||
|
LOG(LS_ERROR) << "ViE SetSendCodec failed";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RtcVideoMediaChannel::SetRender(bool render) {
|
||||||
|
if (video_channel_ != -1) {
|
||||||
|
int ret = -1;
|
||||||
|
if (render == render_started_)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (render) {
|
||||||
|
ret = engine()->video_engine()->render()->StartRender(video_channel_);
|
||||||
|
} else {
|
||||||
|
ret = engine()->video_engine()->render()->StopRender(video_channel_);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret == 0) {
|
||||||
|
render_started_ = render;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RtcVideoMediaChannel::SetSend(bool send) {
|
||||||
|
if (send == sending()) {
|
||||||
|
return true; // no action required
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ret = true;
|
||||||
|
if (send) { //enable
|
||||||
|
if (engine()->video_engine()->base()->StartSend(video_channel_) != 0) {
|
||||||
|
LOG(LS_ERROR) << "ViE StartSend failed";
|
||||||
|
ret = false;
|
||||||
|
}
|
||||||
|
} else { // disable
|
||||||
|
if (engine()->video_engine()->base()->StopSend(video_channel_) != 0) {
|
||||||
|
LOG(LS_ERROR) << "ViE StopSend failed";
|
||||||
|
ret = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ret)
|
||||||
|
sending_ = send;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RtcVideoMediaChannel::AddStream(uint32 ssrc, uint32 voice_ssrc) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RtcVideoMediaChannel::RemoveStream(uint32 ssrc) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RtcVideoMediaChannel::SetRenderer(
|
||||||
|
uint32 ssrc, cricket::VideoRenderer* renderer) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RtcVideoMediaChannel::SetExternalRenderer(uint32 ssrc, void* renderer)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
ret = engine_->video_engine()->render()->AddRenderer(
|
||||||
|
video_channel_,
|
||||||
|
kVideoI420,
|
||||||
|
static_cast<ExternalRenderer*>(renderer));
|
||||||
|
if (ret !=0 )
|
||||||
|
return false;
|
||||||
|
ret = engine_->video_engine()->render()->StartRender(video_channel_);
|
||||||
|
if (ret !=0 )
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RtcVideoMediaChannel::GetStats(cricket::VideoMediaInfo* info) {
|
||||||
|
cricket::VideoSenderInfo sinfo;
|
||||||
|
memset(&sinfo, 0, sizeof(sinfo));
|
||||||
|
|
||||||
|
unsigned int ssrc;
|
||||||
|
if (engine_->video_engine()->rtp()->GetLocalSSRC(video_channel_,
|
||||||
|
ssrc) != 0) {
|
||||||
|
LOG(LS_ERROR) << "ViE GetLocalSSRC failed";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
sinfo.ssrc = ssrc;
|
||||||
|
|
||||||
|
unsigned int cumulative_lost, extended_max, jitter;
|
||||||
|
int rtt_ms;
|
||||||
|
unsigned short fraction_lost;
|
||||||
|
|
||||||
|
if (engine_->video_engine()->rtp()->GetSentRTCPStatistics(video_channel_,
|
||||||
|
fraction_lost, cumulative_lost, extended_max, jitter, rtt_ms) != 0) {
|
||||||
|
LOG(LS_ERROR) << "ViE GetLocalSSRC failed";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
sinfo.fraction_lost = fraction_lost;
|
||||||
|
sinfo.rtt_ms = rtt_ms;
|
||||||
|
|
||||||
|
unsigned int bytes_sent, packets_sent, bytes_recv, packets_recv;
|
||||||
|
if (engine_->video_engine()->rtp()->GetRTPStatistics(video_channel_,
|
||||||
|
bytes_sent, packets_sent, bytes_recv, packets_recv) != 0) {
|
||||||
|
LOG(LS_ERROR) << "ViE GetRTPStatistics";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
sinfo.packets_sent = packets_sent;
|
||||||
|
sinfo.bytes_sent = bytes_sent;
|
||||||
|
sinfo.packets_lost = -1;
|
||||||
|
sinfo.packets_cached = -1;
|
||||||
|
|
||||||
|
info->senders.push_back(sinfo);
|
||||||
|
|
||||||
|
//build receiver info.
|
||||||
|
// reusing the above local variables
|
||||||
|
cricket::VideoReceiverInfo rinfo;
|
||||||
|
memset(&rinfo, 0, sizeof(rinfo));
|
||||||
|
if (engine_->video_engine()->rtp()->GetReceivedRTCPStatistics(video_channel_,
|
||||||
|
fraction_lost, cumulative_lost, extended_max, jitter, rtt_ms) != 0) {
|
||||||
|
LOG(LS_ERROR) << "ViE GetReceivedRTPStatistics Failed";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
rinfo.bytes_rcvd = bytes_recv;
|
||||||
|
rinfo.packets_rcvd = packets_recv;
|
||||||
|
rinfo.fraction_lost = fraction_lost;
|
||||||
|
|
||||||
|
if (engine_->video_engine()->rtp()->GetRemoteSSRC(video_channel_,
|
||||||
|
ssrc) != 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
rinfo.ssrc = ssrc;
|
||||||
|
|
||||||
|
//Get codec for wxh
|
||||||
|
info->receivers.push_back(rinfo);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RtcVideoMediaChannel::SendIntraFrame() {
|
||||||
|
bool ret = true;
|
||||||
|
if (engine()->video_engine()->codec()->SendKeyFrame(video_channel_) != 0) {
|
||||||
|
LOG(LS_ERROR) << "ViE SendKeyFrame failed";
|
||||||
|
ret = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RtcVideoMediaChannel::RequestIntraFrame() {
|
||||||
|
//There is no API exposed to application to request a key frame
|
||||||
|
// ViE does this internally when there are errors from decoder
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RtcVideoMediaChannel::OnPacketReceived(talk_base::Buffer* packet) {
|
||||||
|
engine()->video_engine()->network()->ReceivedRTPPacket(video_channel_,
|
||||||
|
packet->data(),
|
||||||
|
packet->length());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void RtcVideoMediaChannel::OnRtcpReceived(talk_base::Buffer* packet) {
|
||||||
|
engine_->video_engine()->network()->ReceivedRTCPPacket(video_channel_,
|
||||||
|
packet->data(),
|
||||||
|
packet->length());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void RtcVideoMediaChannel::SetSendSsrc(uint32 id) {
|
||||||
|
if (!sending_){
|
||||||
|
if (engine()->video_engine()->rtp()->SetLocalSSRC(video_channel_, id) != 0) {
|
||||||
|
LOG(LS_ERROR) << "ViE SetLocalSSRC failed";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LOG(LS_ERROR) << "Channel already in send state";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RtcVideoMediaChannel::SetRtcpCName(const std::string& cname) {
|
||||||
|
if (engine()->video_engine()->rtp()->SetRTCPCName(video_channel_,
|
||||||
|
cname.c_str()) != 0) {
|
||||||
|
LOG(LS_ERROR) << "ViE SetRTCPCName failed";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RtcVideoMediaChannel::Mute(bool on) {
|
||||||
|
// stop send??
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RtcVideoMediaChannel::SetSendBandwidth(bool autobw, int bps) {
|
||||||
|
LOG(LS_VERBOSE) << "RtcVideoMediaChanne::SetSendBandwidth";
|
||||||
|
|
||||||
|
VideoCodec current = send_codec_;
|
||||||
|
send_codec_.startBitrate = bps;
|
||||||
|
|
||||||
|
if (engine()->video_engine()->codec()->SetSendCodec(video_channel_,
|
||||||
|
send_codec_) != 0) {
|
||||||
|
LOG(LS_ERROR) << "ViE SetSendCodec failed";
|
||||||
|
if (engine()->video_engine()->codec()->SetSendCodec(video_channel_,
|
||||||
|
current) != 0) {
|
||||||
|
// should call be ended in this case?
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RtcVideoMediaChannel::SetOptions(int options) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RtcVideoMediaChannel::EnableRtcp() {
|
||||||
|
engine()->video_engine()->rtp()->SetRTCPStatus(
|
||||||
|
video_channel_, kRtcpCompound_RFC4585);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RtcVideoMediaChannel::EnablePLI() {
|
||||||
|
engine_->video_engine()->rtp()->SetKeyFrameRequestMethod(
|
||||||
|
video_channel_, kViEKeyFrameRequestPliRtcp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RtcVideoMediaChannel::EnableTMMBR() {
|
||||||
|
engine_->video_engine()->rtp()->SetTMMBRStatus(video_channel_, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
int RtcVideoMediaChannel::SendPacket(int channel, const void* data, int len) {
|
||||||
|
if (!network_interface_) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
talk_base::Buffer packet(data, len, cricket::kMaxRtpPacketLen);
|
||||||
|
return network_interface_->SendPacket(&packet) ? len : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int RtcVideoMediaChannel::SendRTCPPacket(int channel,
|
||||||
|
const void* data,
|
||||||
|
int len) {
|
||||||
|
if (!network_interface_) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
talk_base::Buffer packet(data, len, cricket::kMaxRtpPacketLen);
|
||||||
|
return network_interface_->SendRtcp(&packet) ? len : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace webrtc
|
||||||
195
third_party_mods/libjingle/source/talk/app/videomediaengine.h
Normal file
195
third_party_mods/libjingle/source/talk/app/videomediaengine.h
Normal file
@ -0,0 +1,195 @@
|
|||||||
|
/*
|
||||||
|
* libjingle
|
||||||
|
* Copyright 2004--2011, Google Inc.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
* 3. The name of the author may not be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||||
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||||
|
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||||
|
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||||
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||||
|
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||||
|
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TALK_APP_WEBRTC_VIDEOMEDIAENGINE_H_
|
||||||
|
#define TALK_APP_WEBRTC_VIDEOMEDIAENGINE_H_
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "talk/base/scoped_ptr.h"
|
||||||
|
#include "talk/session/phone/videocommon.h"
|
||||||
|
#include "talk/session/phone/codec.h"
|
||||||
|
#include "talk/session/phone/channel.h"
|
||||||
|
#include "talk/session/phone/mediaengine.h"
|
||||||
|
#include "talk/app/videoengine.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace cricket {
|
||||||
|
class VoiceMediaChannel;
|
||||||
|
class Device;
|
||||||
|
class VideoRenderer;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace webrtc {
|
||||||
|
class RtcVideoMediaChannel;
|
||||||
|
class RtcVoiceEngine;
|
||||||
|
class ExternalRenderer;
|
||||||
|
|
||||||
|
class RtcVideoEngine : public ViEBaseObserver, public TraceCallback {
|
||||||
|
public:
|
||||||
|
RtcVideoEngine();
|
||||||
|
explicit RtcVideoEngine(RtcVoiceEngine* voice_engine);
|
||||||
|
~RtcVideoEngine();
|
||||||
|
|
||||||
|
bool Init();
|
||||||
|
void Terminate();
|
||||||
|
|
||||||
|
RtcVideoMediaChannel* CreateChannel(
|
||||||
|
cricket::VoiceMediaChannel* voice_channel);
|
||||||
|
bool FindCodec(const cricket::VideoCodec& codec);
|
||||||
|
bool SetDefaultEncoderConfig(const cricket::VideoEncoderConfig& config);
|
||||||
|
|
||||||
|
void RegisterChannel(RtcVideoMediaChannel* channel);
|
||||||
|
void UnregisterChannel(RtcVideoMediaChannel* channel);
|
||||||
|
|
||||||
|
VideoEngineWrapper* video_engine() { return video_engine_.get(); }
|
||||||
|
int GetLastVideoEngineError();
|
||||||
|
int GetCapabilities();
|
||||||
|
bool SetOptions(int options);
|
||||||
|
//TODO - need to change this interface for webrtc
|
||||||
|
bool SetCaptureDevice(const cricket::Device* device);
|
||||||
|
bool SetVideoRenderer(int channel_id,
|
||||||
|
void* window,
|
||||||
|
unsigned int zOrder,
|
||||||
|
float left,
|
||||||
|
float top,
|
||||||
|
float right,
|
||||||
|
float bottom);
|
||||||
|
bool SetLocalRenderer(cricket::VideoRenderer* renderer);
|
||||||
|
cricket::CaptureResult SetCapture(bool capture);
|
||||||
|
const std::vector<cricket::VideoCodec>& codecs() const;
|
||||||
|
void SetLogging(int min_sev, const char* filter);
|
||||||
|
|
||||||
|
cricket::VideoEncoderConfig& default_encoder_config() {
|
||||||
|
return default_encoder_config_;
|
||||||
|
}
|
||||||
|
cricket::VideoCodec& default_codec() {
|
||||||
|
return default_codec_;
|
||||||
|
}
|
||||||
|
bool SetDefaultCodec(const cricket::VideoCodec& codec);
|
||||||
|
|
||||||
|
void ConvertToCricketVideoCodec(const VideoCodec& in_codec,
|
||||||
|
cricket::VideoCodec& out_codec);
|
||||||
|
|
||||||
|
void ConvertFromCricketVideoCodec(const cricket::VideoCodec& in_codec,
|
||||||
|
VideoCodec& out_codec);
|
||||||
|
|
||||||
|
bool SetCaptureDevice(void* external_capture);
|
||||||
|
|
||||||
|
sigslot::signal1<cricket::CaptureResult> SignalCaptureResult;
|
||||||
|
private:
|
||||||
|
|
||||||
|
struct VideoCodecPref {
|
||||||
|
const char* payload_name;
|
||||||
|
int payload_type;
|
||||||
|
int pref;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const VideoCodecPref kVideoCodecPrefs[];
|
||||||
|
int GetCodecPreference(const char* name);
|
||||||
|
|
||||||
|
void ApplyLogging();
|
||||||
|
bool InitVideoEngine(RtcVoiceEngine* voice_engine);
|
||||||
|
void PerformanceAlarm(const unsigned int cpuLoad);
|
||||||
|
bool ReleaseCaptureDevice();
|
||||||
|
virtual void Print(const TraceLevel level, const char *traceString,
|
||||||
|
const int length);
|
||||||
|
|
||||||
|
typedef std::vector<RtcVideoMediaChannel*> VideoChannels;
|
||||||
|
|
||||||
|
talk_base::scoped_ptr<VideoEngineWrapper> video_engine_;
|
||||||
|
VideoCaptureModule* capture_;
|
||||||
|
int capture_id_;
|
||||||
|
RtcVoiceEngine* voice_engine_;
|
||||||
|
std::vector<cricket::VideoCodec> video_codecs_;
|
||||||
|
VideoChannels channels_;
|
||||||
|
talk_base::CriticalSection channels_cs_;
|
||||||
|
bool initialized_;
|
||||||
|
int log_level_;
|
||||||
|
cricket::VideoEncoderConfig default_encoder_config_;
|
||||||
|
cricket::VideoCodec default_codec_;
|
||||||
|
bool capture_started_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class RtcVideoMediaChannel: public cricket::VideoMediaChannel,
|
||||||
|
public webrtc::Transport {
|
||||||
|
public:
|
||||||
|
RtcVideoMediaChannel(
|
||||||
|
RtcVideoEngine* engine, cricket::VoiceMediaChannel* voice_channel);
|
||||||
|
~RtcVideoMediaChannel();
|
||||||
|
|
||||||
|
bool Init();
|
||||||
|
virtual bool SetRecvCodecs(const std::vector<cricket::VideoCodec> &codecs);
|
||||||
|
virtual bool SetSendCodecs(const std::vector<cricket::VideoCodec> &codecs);
|
||||||
|
virtual bool SetRender(bool render);
|
||||||
|
virtual bool SetSend(bool send);
|
||||||
|
virtual bool AddStream(uint32 ssrc, uint32 voice_ssrc);
|
||||||
|
virtual bool RemoveStream(uint32 ssrc);
|
||||||
|
virtual bool SetRenderer(uint32 ssrc, cricket::VideoRenderer* renderer);
|
||||||
|
virtual bool SetExternalRenderer(uint32 ssrc, void* renderer);
|
||||||
|
virtual bool GetStats(cricket::VideoMediaInfo* info);
|
||||||
|
virtual bool SendIntraFrame();
|
||||||
|
virtual bool RequestIntraFrame();
|
||||||
|
|
||||||
|
virtual void OnPacketReceived(talk_base::Buffer* packet);
|
||||||
|
virtual void OnRtcpReceived(talk_base::Buffer* packet);
|
||||||
|
virtual void SetSendSsrc(uint32 id);
|
||||||
|
virtual bool SetRtcpCName(const std::string& cname);
|
||||||
|
virtual bool Mute(bool on);
|
||||||
|
virtual bool SetRecvRtpHeaderExtensions(
|
||||||
|
const std::vector<cricket::RtpHeaderExtension>& extensions) { return false; }
|
||||||
|
virtual bool SetSendRtpHeaderExtensions(
|
||||||
|
const std::vector<cricket::RtpHeaderExtension>& extensions) { return false; }
|
||||||
|
virtual bool SetSendBandwidth(bool autobw, int bps);
|
||||||
|
virtual bool SetOptions(int options);
|
||||||
|
|
||||||
|
RtcVideoEngine* engine() { return engine_; }
|
||||||
|
cricket::VoiceMediaChannel* voice_channel() { return voice_channel_; }
|
||||||
|
int video_channel() { return video_channel_; }
|
||||||
|
bool sending() { return sending_; }
|
||||||
|
int GetMediaChannelId() { return video_channel_; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual int SendPacket(int channel, const void* data, int len);
|
||||||
|
virtual int SendRTCPPacket(int channel, const void* data, int len);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void EnableRtcp();
|
||||||
|
void EnablePLI();
|
||||||
|
void EnableTMMBR();
|
||||||
|
|
||||||
|
RtcVideoEngine* engine_;
|
||||||
|
cricket::VoiceMediaChannel* voice_channel_;
|
||||||
|
int video_channel_;
|
||||||
|
bool sending_;
|
||||||
|
bool render_started_;
|
||||||
|
webrtc::VideoCodec send_codec_;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* TALK_APP_WEBRTC_VIDEOMEDIAENGINE_H_ */
|
||||||
159
third_party_mods/libjingle/source/talk/app/voiceengine.h
Normal file
159
third_party_mods/libjingle/source/talk/app/voiceengine.h
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
/*
|
||||||
|
* libjingle
|
||||||
|
* Copyright 2004--2011, Google Inc.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
* 3. The name of the author may not be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||||
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||||
|
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||||
|
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||||
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||||
|
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||||
|
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef TALK_APP_WEBRTC_VOICEENGINE_H_
|
||||||
|
#define TALK_APP_WEBRTC_VOICEENGINE_H_
|
||||||
|
|
||||||
|
#include "talk/base/common.h"
|
||||||
|
#include "common_types.h"
|
||||||
|
#include "voice_engine/main/interface/voe_base.h"
|
||||||
|
#include "voice_engine/main/interface/voe_codec.h"
|
||||||
|
#include "voice_engine/main/interface/voe_errors.h"
|
||||||
|
#include "voice_engine/main/interface/voe_file.h"
|
||||||
|
#include "voice_engine/main/interface/voe_hardware.h"
|
||||||
|
#include "voice_engine/main/interface/voe_network.h"
|
||||||
|
#include "voice_engine/main/interface/voe_rtp_rtcp.h"
|
||||||
|
#include "voice_engine/main/interface/voe_video_sync.h"
|
||||||
|
#include "voice_engine/main/interface/voe_volume_control.h"
|
||||||
|
|
||||||
|
namespace webrtc {
|
||||||
|
|
||||||
|
// Tracing helpers, for easy logging when WebRTC calls fail.
|
||||||
|
// Example: "LOG_RTCERR1(StartSend, channel);" produces the trace
|
||||||
|
// "StartSend(1) failed, err=XXXX"
|
||||||
|
// The method GetLastRtcError must be defined in the calling scope.
|
||||||
|
#define LOG_RTCERR0(func) \
|
||||||
|
LOG_RTCERR0_EX(func, GetLastRtcError())
|
||||||
|
#define LOG_RTCERR1(func, a1) \
|
||||||
|
LOG_RTCERR1_EX(func, a1, GetLastRtcError())
|
||||||
|
#define LOG_RTCERR2(func, a1, a2) \
|
||||||
|
LOG_RTCERR2_EX(func, a1, a2, GetLastRtcError())
|
||||||
|
#define LOG_RTCERR3(func, a1, a2, a3) \
|
||||||
|
LOG_RTCERR3_EX(func, a1, a2, a3, GetLastRtcError())
|
||||||
|
#define LOG_RTCERR0_EX(func, err) LOG(WARNING) \
|
||||||
|
<< "" << #func << "() failed, err=" << err
|
||||||
|
#define LOG_RTCERR1_EX(func, a1, err) LOG(WARNING) \
|
||||||
|
<< "" << #func << "(" << a1 << ") failed, err=" << err
|
||||||
|
#define LOG_RTCERR2_EX(func, a1, a2, err) LOG(WARNING) \
|
||||||
|
<< "" << #func << "(" << a1 << ", " << a2 << ") failed, err=" \
|
||||||
|
<< err
|
||||||
|
#define LOG_RTCERR3_EX(func, a1, a2, a3, err) LOG(WARNING) \
|
||||||
|
<< "" << #func << "(" << a1 << ", " << a2 << ", " << a3 \
|
||||||
|
<< ") failed, err=" << err
|
||||||
|
|
||||||
|
// automatically handles lifetime of WebRtc VoiceEngine
|
||||||
|
class scoped_webrtc_engine {
|
||||||
|
public:
|
||||||
|
explicit scoped_webrtc_engine(VoiceEngine* e) : ptr(e) {}
|
||||||
|
// VERIFY, to ensure that there are no leaks at shutdown
|
||||||
|
~scoped_webrtc_engine() { if (ptr) VERIFY(VoiceEngine::Delete(ptr)); }
|
||||||
|
VoiceEngine* get() const { return ptr; }
|
||||||
|
private:
|
||||||
|
VoiceEngine* ptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
// scoped_ptr class to handle obtaining and releasing WebRTC interface pointers
|
||||||
|
template<class T>
|
||||||
|
class scoped_rtc_ptr {
|
||||||
|
public:
|
||||||
|
explicit scoped_rtc_ptr(const scoped_webrtc_engine& e)
|
||||||
|
: ptr(T::GetInterface(e.get())) {}
|
||||||
|
template <typename E>
|
||||||
|
explicit scoped_rtc_ptr(E* engine) : ptr(T::GetInterface(engine)) {}
|
||||||
|
explicit scoped_rtc_ptr(T* p) : ptr(p) {}
|
||||||
|
~scoped_rtc_ptr() { if (ptr) ptr->Release(); }
|
||||||
|
T* operator->() const { return ptr; }
|
||||||
|
T* get() const { return ptr; }
|
||||||
|
|
||||||
|
// Queries the engine for the wrapped type and releases the current pointer.
|
||||||
|
template <typename E>
|
||||||
|
void reset(E* engine) {
|
||||||
|
reset();
|
||||||
|
if (engine)
|
||||||
|
ptr = T::GetInterface(engine);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Releases the current pointer.
|
||||||
|
void reset() {
|
||||||
|
if (ptr) {
|
||||||
|
ptr->Release();
|
||||||
|
ptr = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
T* ptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Utility class for aggregating the various WebRTC interface.
|
||||||
|
// Fake implementations can also be injected for testing.
|
||||||
|
class RtcWrapper {
|
||||||
|
public:
|
||||||
|
RtcWrapper()
|
||||||
|
: engine_(VoiceEngine::Create()),
|
||||||
|
base_(engine_), codec_(engine_), file_(engine_),
|
||||||
|
hw_(engine_), network_(engine_), rtp_(engine_),
|
||||||
|
sync_(engine_), volume_(engine_) {
|
||||||
|
|
||||||
|
}
|
||||||
|
RtcWrapper(VoEBase* base, VoECodec* codec, VoEFile* file,
|
||||||
|
VoEHardware* hw, VoENetwork* network,
|
||||||
|
VoERTP_RTCP* rtp, VoEVideoSync* sync,
|
||||||
|
VoEVolumeControl* volume)
|
||||||
|
: engine_(NULL),
|
||||||
|
base_(base), codec_(codec), file_(file),
|
||||||
|
hw_(hw), network_(network), rtp_(rtp),
|
||||||
|
sync_(sync), volume_(volume) {
|
||||||
|
|
||||||
|
}
|
||||||
|
virtual ~RtcWrapper() {}
|
||||||
|
VoiceEngine* engine() { return engine_.get(); }
|
||||||
|
VoEBase* base() { return base_.get(); }
|
||||||
|
VoECodec* codec() { return codec_.get(); }
|
||||||
|
VoEFile* file() { return file_.get(); }
|
||||||
|
VoEHardware* hw() { return hw_.get(); }
|
||||||
|
VoENetwork* network() { return network_.get(); }
|
||||||
|
VoERTP_RTCP* rtp() { return rtp_.get(); }
|
||||||
|
VoEVideoSync* sync() { return sync_.get(); }
|
||||||
|
VoEVolumeControl* volume() { return volume_.get(); }
|
||||||
|
int error() { return base_->LastError(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
scoped_webrtc_engine engine_;
|
||||||
|
scoped_rtc_ptr<VoEBase> base_;
|
||||||
|
scoped_rtc_ptr<VoECodec> codec_;
|
||||||
|
scoped_rtc_ptr<VoEFile> file_;
|
||||||
|
scoped_rtc_ptr<VoEHardware> hw_;
|
||||||
|
scoped_rtc_ptr<VoENetwork> network_;
|
||||||
|
scoped_rtc_ptr<VoERTP_RTCP> rtp_;
|
||||||
|
scoped_rtc_ptr<VoEVideoSync> sync_;
|
||||||
|
scoped_rtc_ptr<VoEVolumeControl> volume_;
|
||||||
|
};
|
||||||
|
} //namespace webrtc
|
||||||
|
|
||||||
|
#endif // TALK_APP_WEBRTC_VOICEENGINE_H_
|
||||||
966
third_party_mods/libjingle/source/talk/app/voicemediaengine.cc
Normal file
966
third_party_mods/libjingle/source/talk/app/voicemediaengine.cc
Normal file
@ -0,0 +1,966 @@
|
|||||||
|
/*
|
||||||
|
* libjingle
|
||||||
|
* Copyright 2004--2011, Google Inc.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
* 3. The name of the author may not be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||||
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||||
|
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||||
|
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||||
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||||
|
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||||
|
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "talk/app/voicemediaengine.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cstdio>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#ifdef PLATFORM_CHROMIUM
|
||||||
|
#include "content/renderer/renderer_webrtc_audio_device_impl.h"
|
||||||
|
#else
|
||||||
|
#include "modules/audio_device/main/interface/audio_device.h"
|
||||||
|
#endif
|
||||||
|
#include "talk/base/base64.h"
|
||||||
|
#include "talk/base/byteorder.h"
|
||||||
|
#include "talk/base/common.h"
|
||||||
|
#include "talk/base/helpers.h"
|
||||||
|
#include "talk/base/logging.h"
|
||||||
|
#include "talk/base/stringencode.h"
|
||||||
|
|
||||||
|
namespace webrtc {
|
||||||
|
|
||||||
|
static void LogMultiline(talk_base::LoggingSeverity sev, char* text) {
|
||||||
|
const char* delim = "\r\n";
|
||||||
|
for (char* tok = strtok(text, delim); tok; tok = strtok(NULL, delim)) {
|
||||||
|
LOG_V(sev) << tok;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// RtcVoiceEngine
|
||||||
|
const RtcVoiceEngine::CodecPref RtcVoiceEngine::kCodecPrefs[] = {
|
||||||
|
{ "ISAC", 16000 },
|
||||||
|
{ "ISAC", 32000 },
|
||||||
|
{ "ISACLC", 16000 },
|
||||||
|
{ "speex", 16000 },
|
||||||
|
{ "IPCMWB", 16000 },
|
||||||
|
{ "G722", 16000 },
|
||||||
|
{ "iLBC", 8000 },
|
||||||
|
{ "speex", 8000 },
|
||||||
|
{ "GSM", 8000 },
|
||||||
|
{ "EG711U", 8000 },
|
||||||
|
{ "EG711A", 8000 },
|
||||||
|
{ "PCMU", 8000 },
|
||||||
|
{ "PCMA", 8000 },
|
||||||
|
{ "CN", 32000 },
|
||||||
|
{ "CN", 16000 },
|
||||||
|
{ "CN", 8000 },
|
||||||
|
{ "red", 8000 },
|
||||||
|
{ "telephone-event", 8000 },
|
||||||
|
};
|
||||||
|
|
||||||
|
RtcVoiceEngine::RtcVoiceEngine()
|
||||||
|
: rtc_wrapper_(new RtcWrapper()),
|
||||||
|
log_level_(kDefaultLogSeverity),
|
||||||
|
adm_(NULL) {
|
||||||
|
Construct();
|
||||||
|
}
|
||||||
|
|
||||||
|
RtcVoiceEngine::RtcVoiceEngine(RtcWrapper* rtc_wrapper)
|
||||||
|
: rtc_wrapper_(rtc_wrapper),
|
||||||
|
log_level_(kDefaultLogSeverity),
|
||||||
|
adm_(NULL) {
|
||||||
|
Construct();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RtcVoiceEngine::Construct() {
|
||||||
|
LOG(INFO) << "RtcVoiceEngine::RtcVoiceEngine";
|
||||||
|
ApplyLogging();
|
||||||
|
|
||||||
|
if (rtc_wrapper_->base()->RegisterVoiceEngineObserver(*this) == -1) {
|
||||||
|
LOG_RTCERR0(RegisterVoiceEngineObserver);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load our audio codec list
|
||||||
|
LOG(INFO) << "WebRTC VoiceEngine codecs:";
|
||||||
|
int ncodecs = rtc_wrapper_->codec()->NumOfCodecs();
|
||||||
|
for (int i = 0; i < ncodecs; ++i) {
|
||||||
|
CodecInst gcodec;
|
||||||
|
if (rtc_wrapper_->codec()->GetCodec(i, gcodec) >= 0) {
|
||||||
|
int pref = GetCodecPreference(gcodec.plname, gcodec.plfreq);
|
||||||
|
if (pref != -1) {
|
||||||
|
if (gcodec.rate == -1) gcodec.rate = 0;
|
||||||
|
cricket::AudioCodec codec(gcodec.pltype, gcodec.plname, gcodec.plfreq,
|
||||||
|
gcodec.rate, gcodec.channels, pref);
|
||||||
|
LOG(INFO) << gcodec.plname << "/" << gcodec.plfreq << "/" \
|
||||||
|
<< gcodec.channels << " " << gcodec.pltype;
|
||||||
|
codecs_.push_back(codec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Make sure they are in local preference order
|
||||||
|
std::sort(codecs_.begin(), codecs_.end(), &cricket::AudioCodec::Preferable);
|
||||||
|
}
|
||||||
|
|
||||||
|
RtcVoiceEngine::~RtcVoiceEngine() {
|
||||||
|
LOG(INFO) << "RtcVoiceEngine::~RtcVoiceEngine";
|
||||||
|
if (rtc_wrapper_->base()->DeRegisterVoiceEngineObserver() == -1) {
|
||||||
|
LOG_RTCERR0(DeRegisterVoiceEngineObserver);
|
||||||
|
}
|
||||||
|
rtc_wrapper_.reset();
|
||||||
|
if (adm_) {
|
||||||
|
AudioDeviceModule::Destroy(adm_);
|
||||||
|
adm_ = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RtcVoiceEngine::Init() {
|
||||||
|
LOG(INFO) << "RtcVoiceEngine::Init";
|
||||||
|
bool res = InitInternal();
|
||||||
|
if (res) {
|
||||||
|
LOG(INFO) << "RtcVoiceEngine::Init Done!";
|
||||||
|
} else {
|
||||||
|
LOG(LERROR) << "RtcVoiceEngine::Init failed";
|
||||||
|
Terminate();
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RtcVoiceEngine::InitInternal() {
|
||||||
|
// Temporarily turn logging level up for the Init call
|
||||||
|
int old_level = log_level_;
|
||||||
|
log_level_ = talk_base::_min(log_level_,
|
||||||
|
static_cast<int>(talk_base::INFO));
|
||||||
|
ApplyLogging();
|
||||||
|
|
||||||
|
if (!adm_) {
|
||||||
|
#ifdef PLATFORM_CHROMIUM
|
||||||
|
adm_ = new RendererWebRtcAudioDeviceImpl(1440, 1440, 1, 1, 48000, 48000);
|
||||||
|
#else
|
||||||
|
adm_ = AudioDeviceModule::Create(0);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (rtc_wrapper_->base()->RegisterAudioDeviceModule(*adm_) == -1) {
|
||||||
|
LOG_RTCERR0_EX(Init, rtc_wrapper_->error());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Init WebRTC VoiceEngine, enabling AEC logging if specified in SetLogging.
|
||||||
|
if (rtc_wrapper_->base()->Init() == -1) {
|
||||||
|
LOG_RTCERR0_EX(Init, rtc_wrapper_->error());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restore the previous log level
|
||||||
|
log_level_ = old_level;
|
||||||
|
ApplyLogging();
|
||||||
|
|
||||||
|
// Log the WebRTC version info
|
||||||
|
char buffer[1024] = "";
|
||||||
|
rtc_wrapper_->base()->GetVersion(buffer);
|
||||||
|
LOG(INFO) << "WebRTC VoiceEngine Version:";
|
||||||
|
LogMultiline(talk_base::INFO, buffer);
|
||||||
|
|
||||||
|
// Turn on AEC and AGC by default.
|
||||||
|
if (!SetOptions(
|
||||||
|
cricket::MediaEngine::ECHO_CANCELLATION | cricket::MediaEngine::AUTO_GAIN_CONTROL)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print our codec list again for the call diagnostic log
|
||||||
|
LOG(INFO) << "WebRTC VoiceEngine codecs:";
|
||||||
|
for (std::vector<cricket::AudioCodec>::const_iterator it = codecs_.begin();
|
||||||
|
it != codecs_.end(); ++it) {
|
||||||
|
LOG(INFO) << it->name << "/" << it->clockrate << "/"
|
||||||
|
<< it->channels << " " << it->id;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RtcVoiceEngine::SetDevices(const cricket::Device* in_device,
|
||||||
|
const cricket::Device* out_device) {
|
||||||
|
LOG(INFO) << "RtcVoiceEngine::SetDevices";
|
||||||
|
// Currently we always use the default device, so do nothing here.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RtcVoiceEngine::Terminate() {
|
||||||
|
LOG(INFO) << "RtcVoiceEngine::Terminate";
|
||||||
|
|
||||||
|
rtc_wrapper_->base()->Terminate();
|
||||||
|
}
|
||||||
|
|
||||||
|
int RtcVoiceEngine::GetCapabilities() {
|
||||||
|
return cricket::MediaEngine::AUDIO_SEND | cricket::MediaEngine::AUDIO_RECV;
|
||||||
|
}
|
||||||
|
|
||||||
|
cricket::VoiceMediaChannel *RtcVoiceEngine::CreateChannel() {
|
||||||
|
RtcVoiceMediaChannel* ch = new RtcVoiceMediaChannel(this);
|
||||||
|
if (!ch->valid()) {
|
||||||
|
delete ch;
|
||||||
|
ch = NULL;
|
||||||
|
}
|
||||||
|
return ch;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RtcVoiceEngine::SetOptions(int options) {
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RtcVoiceEngine::FindAudioDeviceId(
|
||||||
|
bool is_input, const std::string& dev_name, int dev_id, int* rtc_id) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RtcVoiceEngine::GetOutputVolume(int* level) {
|
||||||
|
unsigned int ulevel;
|
||||||
|
if (rtc_wrapper_->volume()->GetSpeakerVolume(ulevel) == -1) {
|
||||||
|
LOG_RTCERR1(GetSpeakerVolume, level);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
*level = ulevel;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RtcVoiceEngine::SetOutputVolume(int level) {
|
||||||
|
ASSERT(level >= 0 && level <= 255);
|
||||||
|
if (rtc_wrapper_->volume()->SetSpeakerVolume(level) == -1) {
|
||||||
|
LOG_RTCERR1(SetSpeakerVolume, level);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int RtcVoiceEngine::GetInputLevel() {
|
||||||
|
unsigned int ulevel;
|
||||||
|
return (rtc_wrapper_->volume()->GetSpeechInputLevel(ulevel) != -1) ?
|
||||||
|
static_cast<int>(ulevel) : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RtcVoiceEngine::SetLocalMonitor(bool enable) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<cricket::AudioCodec>& RtcVoiceEngine::codecs() {
|
||||||
|
return codecs_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RtcVoiceEngine::FindCodec(const cricket::AudioCodec& in) {
|
||||||
|
return FindRtcCodec(in, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RtcVoiceEngine::FindRtcCodec(const cricket::AudioCodec& in, CodecInst* out) {
|
||||||
|
int ncodecs = rtc_wrapper_->codec()->NumOfCodecs();
|
||||||
|
for (int i = 0; i < ncodecs; ++i) {
|
||||||
|
CodecInst gcodec;
|
||||||
|
if (rtc_wrapper_->codec()->GetCodec(i, gcodec) >= 0) {
|
||||||
|
cricket::AudioCodec codec(gcodec.pltype, gcodec.plname,
|
||||||
|
gcodec.plfreq, gcodec.rate, gcodec.channels, 0);
|
||||||
|
if (codec.Matches(in)) {
|
||||||
|
if (out) {
|
||||||
|
// If the codec is VBR and an explicit rate is specified, use it.
|
||||||
|
if (in.bitrate != 0 && gcodec.rate == -1) {
|
||||||
|
gcodec.rate = in.bitrate;
|
||||||
|
}
|
||||||
|
*out = gcodec;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RtcVoiceEngine::SetLogging(int min_sev, const char* filter) {
|
||||||
|
log_level_ = min_sev;
|
||||||
|
|
||||||
|
std::vector<std::string> opts;
|
||||||
|
talk_base::tokenize(filter, ' ', &opts);
|
||||||
|
|
||||||
|
// voice log level
|
||||||
|
ApplyLogging();
|
||||||
|
}
|
||||||
|
|
||||||
|
int RtcVoiceEngine::GetLastRtcError() {
|
||||||
|
return rtc_wrapper_->error();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RtcVoiceEngine::ApplyLogging() {
|
||||||
|
int filter = 0;
|
||||||
|
switch (log_level_) {
|
||||||
|
case talk_base::INFO: filter |= kTraceAll; // fall through
|
||||||
|
case talk_base::WARNING: filter |= kTraceWarning; // fall through
|
||||||
|
case talk_base::LERROR: filter |= kTraceError | kTraceCritical;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RtcVoiceEngine::Print(const TraceLevel level,
|
||||||
|
const char* traceString, const int length) {
|
||||||
|
talk_base::LoggingSeverity sev = talk_base::INFO;
|
||||||
|
if (level == kTraceError || level == kTraceCritical)
|
||||||
|
sev = talk_base::LERROR;
|
||||||
|
else if (level == kTraceWarning)
|
||||||
|
sev = talk_base::WARNING;
|
||||||
|
else if (level == kTraceStateInfo)
|
||||||
|
sev = talk_base::INFO;
|
||||||
|
|
||||||
|
if (sev >= log_level_) {
|
||||||
|
// Skip past webrtc boilerplate prefix text
|
||||||
|
if (length <= 70) {
|
||||||
|
std::string msg(traceString, length);
|
||||||
|
LOG(LERROR) << "Malformed WebRTC log message: ";
|
||||||
|
LOG_V(sev) << msg;
|
||||||
|
} else {
|
||||||
|
std::string msg(traceString + 70, length - 71);
|
||||||
|
LOG_V(sev) << "VoE:" << msg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RtcVoiceEngine::CallbackOnError(const int err_code,
|
||||||
|
const int channel_num) {
|
||||||
|
talk_base::CritScope lock(&channels_cs_);
|
||||||
|
RtcVoiceMediaChannel* channel = NULL;
|
||||||
|
uint32 ssrc = 0;
|
||||||
|
LOG(WARNING) << "WebRTC error " << err_code << " reported on channel "
|
||||||
|
<< channel_num << ".";
|
||||||
|
if (FindChannelAndSsrc(channel_num, &channel, &ssrc)) {
|
||||||
|
ASSERT(channel != NULL);
|
||||||
|
channel->OnError(ssrc, err_code);
|
||||||
|
} else {
|
||||||
|
LOG(LERROR) << "WebRTC channel " << channel_num
|
||||||
|
<< " could not be found in the channel list when error reported.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int RtcVoiceEngine::GetCodecPreference(const char *name, int clockrate) {
|
||||||
|
for (size_t i = 0; i < ARRAY_SIZE(kCodecPrefs); ++i) {
|
||||||
|
if ((strcmp(kCodecPrefs[i].name, name) == 0) &&
|
||||||
|
(kCodecPrefs[i].clockrate == clockrate))
|
||||||
|
return ARRAY_SIZE(kCodecPrefs) - i;
|
||||||
|
}
|
||||||
|
LOG(WARNING) << "Unexpected codec \"" << name << "/" << clockrate << "\"";
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RtcVoiceEngine::FindChannelAndSsrc(
|
||||||
|
int channel_num, RtcVoiceMediaChannel** channel, uint32* ssrc) const {
|
||||||
|
ASSERT(channel != NULL && ssrc != NULL);
|
||||||
|
|
||||||
|
*channel = NULL;
|
||||||
|
*ssrc = 0;
|
||||||
|
// Find corresponding channel and ssrc
|
||||||
|
for (ChannelList::const_iterator it = channels_.begin();
|
||||||
|
it != channels_.end(); ++it) {
|
||||||
|
ASSERT(*it != NULL);
|
||||||
|
if ((*it)->FindSsrc(channel_num, ssrc)) {
|
||||||
|
*channel = *it;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RtcVoiceEngine::RegisterChannel(RtcVoiceMediaChannel *channel) {
|
||||||
|
talk_base::CritScope lock(&channels_cs_);
|
||||||
|
channels_.push_back(channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RtcVoiceEngine::UnregisterChannel(RtcVoiceMediaChannel *channel) {
|
||||||
|
talk_base::CritScope lock(&channels_cs_);
|
||||||
|
ChannelList::iterator i = std::find(channels_.begin(),
|
||||||
|
channels_.end(),
|
||||||
|
channel);
|
||||||
|
if (i != channels_.end()) {
|
||||||
|
channels_.erase(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// RtcVoiceMediaChannel
|
||||||
|
RtcVoiceMediaChannel::RtcVoiceMediaChannel(RtcVoiceEngine *engine)
|
||||||
|
: RtcMediaChannel<cricket::VoiceMediaChannel, RtcVoiceEngine>(engine,
|
||||||
|
engine->webrtc()->base()->CreateChannel()),
|
||||||
|
channel_options_(0), playout_(false), send_(cricket::SEND_NOTHING) {
|
||||||
|
engine->RegisterChannel(this);
|
||||||
|
LOG(INFO) << "RtcVoiceMediaChannel::RtcVoiceMediaChannel "
|
||||||
|
<< audio_channel();
|
||||||
|
|
||||||
|
// Register external transport
|
||||||
|
if (engine->webrtc()->network()->RegisterExternalTransport(
|
||||||
|
audio_channel(), *static_cast<Transport*>(this)) == -1) {
|
||||||
|
LOG_RTCERR2(RegisterExternalTransport, audio_channel(), this);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enable RTCP (for quality stats and feedback messages)
|
||||||
|
EnableRtcp(audio_channel());
|
||||||
|
|
||||||
|
// Create a random but nonzero send SSRC
|
||||||
|
SetSendSsrc(talk_base::CreateRandomNonZeroId());
|
||||||
|
}
|
||||||
|
|
||||||
|
RtcVoiceMediaChannel::~RtcVoiceMediaChannel() {
|
||||||
|
LOG(INFO) << "RtcVoiceMediaChannel::~RtcVoiceMediaChannel "
|
||||||
|
<< audio_channel();
|
||||||
|
|
||||||
|
// DeRegister external transport
|
||||||
|
if (engine()->webrtc()->network()->DeRegisterExternalTransport(
|
||||||
|
audio_channel()) == -1) {
|
||||||
|
LOG_RTCERR1(DeRegisterExternalTransport, audio_channel());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unregister ourselves from the engine.
|
||||||
|
engine()->UnregisterChannel(this);
|
||||||
|
// Remove any remaining streams.
|
||||||
|
while (!mux_channels_.empty()) {
|
||||||
|
RemoveStream(mux_channels_.begin()->first);
|
||||||
|
}
|
||||||
|
// Delete the primary channel.
|
||||||
|
if (engine()->webrtc()->base()->DeleteChannel(audio_channel()) == -1) {
|
||||||
|
LOG_RTCERR1(DeleteChannel, audio_channel());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RtcVoiceMediaChannel::SetOptions(int flags) {
|
||||||
|
// Always accept flags that are unchanged.
|
||||||
|
if (channel_options_ == flags) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reject new options if we're already sending.
|
||||||
|
if (send_ != cricket::SEND_NOTHING) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Save the options, to be interpreted where appropriate.
|
||||||
|
channel_options_ = flags;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RtcVoiceMediaChannel::SetRecvCodecs(
|
||||||
|
const std::vector<cricket::AudioCodec>& codecs) {
|
||||||
|
// Update our receive payload types to match what we offered. This only is
|
||||||
|
// an issue when a different entity (i.e. a server) is generating the offer
|
||||||
|
// for us.
|
||||||
|
bool ret = true;
|
||||||
|
for (std::vector<cricket::AudioCodec>::const_iterator i = codecs.begin();
|
||||||
|
i != codecs.end() && ret; ++i) {
|
||||||
|
CodecInst gcodec;
|
||||||
|
if (engine()->FindRtcCodec(*i, &gcodec)) {
|
||||||
|
if (gcodec.pltype != i->id) {
|
||||||
|
LOG(INFO) << "Updating payload type for " << gcodec.plname
|
||||||
|
<< " from " << gcodec.pltype << " to " << i->id;
|
||||||
|
gcodec.pltype = i->id;
|
||||||
|
if (engine()->webrtc()->codec()->SetRecPayloadType(
|
||||||
|
audio_channel(), gcodec) == -1) {
|
||||||
|
LOG_RTCERR1(SetRecPayloadType, audio_channel());
|
||||||
|
ret = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LOG(WARNING) << "Unknown codec " << i->name;
|
||||||
|
ret = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RtcVoiceMediaChannel::SetSendCodecs(
|
||||||
|
const std::vector<cricket::AudioCodec>& codecs) {
|
||||||
|
bool first = true;
|
||||||
|
CodecInst send_codec;
|
||||||
|
memset(&send_codec, 0, sizeof(send_codec));
|
||||||
|
|
||||||
|
for (std::vector<cricket::AudioCodec>::const_iterator i = codecs.begin();
|
||||||
|
i != codecs.end(); ++i) {
|
||||||
|
CodecInst gcodec;
|
||||||
|
if (!engine()->FindRtcCodec(*i, &gcodec))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// We'll use the first codec in the list to actually send audio data.
|
||||||
|
// Be sure to use the payload type requested by the remote side.
|
||||||
|
if (first) {
|
||||||
|
send_codec = gcodec;
|
||||||
|
send_codec.pltype = i->id;
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we're being asked to set an empty list of codecs, due to a buggy client,
|
||||||
|
// choose the most common format: PCMU
|
||||||
|
if (first) {
|
||||||
|
LOG(WARNING) << "Received empty list of codecs; using PCMU/8000";
|
||||||
|
cricket::AudioCodec codec(0, "PCMU", 8000, 0, 1, 0);
|
||||||
|
engine()->FindRtcCodec(codec, &send_codec);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the codec.
|
||||||
|
LOG(INFO) << "Selected voice codec " << send_codec.plname
|
||||||
|
<< "/" << send_codec.plfreq;
|
||||||
|
if (engine()->webrtc()->codec()->SetSendCodec(audio_channel(),
|
||||||
|
send_codec) == -1) {
|
||||||
|
LOG_RTCERR1(SetSendCodec, audio_channel());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RtcVoiceMediaChannel::SetPlayout(bool playout) {
|
||||||
|
if (playout_ == playout) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool result = true;
|
||||||
|
if (mux_channels_.empty()) {
|
||||||
|
// Only toggle the default channel if we don't have any other channels.
|
||||||
|
result = SetPlayout(audio_channel(), playout);
|
||||||
|
}
|
||||||
|
for (ChannelMap::iterator it = mux_channels_.begin();
|
||||||
|
it != mux_channels_.end() && result; ++it) {
|
||||||
|
if (!SetPlayout(it->second, playout)) {
|
||||||
|
LOG(LERROR) << "SetPlayout " << playout << " on channel " << it->second
|
||||||
|
<< " failed";
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result) {
|
||||||
|
playout_ = playout;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RtcVoiceMediaChannel::GetPlayout() {
|
||||||
|
return playout_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RtcVoiceMediaChannel::SetSend(cricket::SendFlags send) {
|
||||||
|
if (send_ == send) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (send == cricket::SEND_MICROPHONE) {
|
||||||
|
if (sequence_number() != -1) {
|
||||||
|
if (engine()->webrtc()->sync()->SetInitSequenceNumber(
|
||||||
|
audio_channel(), sequence_number() + 1) == -1) {
|
||||||
|
LOG_RTCERR2(SetInitSequenceNumber, audio_channel(),
|
||||||
|
sequence_number() + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (engine()->webrtc()->base()->StartSend(audio_channel()) == -1) {
|
||||||
|
LOG_RTCERR1(StartSend, audio_channel());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (engine()->webrtc()->file()->StopPlayingFileAsMicrophone(
|
||||||
|
audio_channel()) == -1) {
|
||||||
|
LOG_RTCERR1(StopPlayingFileAsMicrophone, audio_channel());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else { // SEND_NOTHING
|
||||||
|
if (engine()->webrtc()->base()->StopSend(audio_channel()) == -1) {
|
||||||
|
LOG_RTCERR1(StopSend, audio_channel());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
send_ = send;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
cricket::SendFlags RtcVoiceMediaChannel::GetSend() {
|
||||||
|
return send_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RtcVoiceMediaChannel::AddStream(uint32 ssrc) {
|
||||||
|
talk_base::CritScope lock(&mux_channels_cs_);
|
||||||
|
|
||||||
|
if (mux_channels_.find(ssrc) != mux_channels_.end()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new channel for receiving audio data.
|
||||||
|
int channel = engine()->webrtc()->base()->CreateChannel();
|
||||||
|
if (channel == -1) {
|
||||||
|
LOG_RTCERR0(CreateChannel);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configure to use external transport, like our default channel.
|
||||||
|
if (engine()->webrtc()->network()->RegisterExternalTransport(
|
||||||
|
channel, *this) == -1) {
|
||||||
|
LOG_RTCERR2(SetExternalTransport, channel, this);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use the same SSRC as our default channel (so the RTCP reports are correct).
|
||||||
|
unsigned int send_ssrc;
|
||||||
|
VoERTP_RTCP* rtp = engine()->webrtc()->rtp();
|
||||||
|
if (rtp->GetLocalSSRC(audio_channel(), send_ssrc) == -1) {
|
||||||
|
LOG_RTCERR2(GetSendSSRC, channel, send_ssrc);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (rtp->SetLocalSSRC(channel, send_ssrc) == -1) {
|
||||||
|
LOG_RTCERR2(SetSendSSRC, channel, send_ssrc);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mux_channels_.empty() && GetPlayout()) {
|
||||||
|
LOG(INFO) << "Disabling playback on the default voice channel";
|
||||||
|
SetPlayout(audio_channel(), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
mux_channels_[ssrc] = channel;
|
||||||
|
|
||||||
|
LOG(INFO) << "New audio stream " << ssrc << " registered to WebRTC channel #"
|
||||||
|
<< channel << ".";
|
||||||
|
return SetPlayout(channel, playout_);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RtcVoiceMediaChannel::RemoveStream(uint32 ssrc) {
|
||||||
|
talk_base::CritScope lock(&mux_channels_cs_);
|
||||||
|
ChannelMap::iterator it = mux_channels_.find(ssrc);
|
||||||
|
|
||||||
|
if (it != mux_channels_.end()) {
|
||||||
|
if (engine()->webrtc()->network()->DeRegisterExternalTransport(
|
||||||
|
it->second) == -1) {
|
||||||
|
LOG_RTCERR1(DeRegisterExternalTransport, it->second);
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG(INFO) << "Removing audio stream " << ssrc << " with WebRTC channel #"
|
||||||
|
<< it->second << ".";
|
||||||
|
if (engine()->webrtc()->base()->DeleteChannel(it->second) == -1) {
|
||||||
|
LOG_RTCERR1(DeleteChannel, audio_channel());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
mux_channels_.erase(it);
|
||||||
|
if (mux_channels_.empty() && GetPlayout()) {
|
||||||
|
// The last stream was removed. We can now enable the default
|
||||||
|
// channel for new channels to be played out immediately without
|
||||||
|
// waiting for AddStream messages.
|
||||||
|
// TODO(oja): Does the default channel still have it's CN state?
|
||||||
|
LOG(INFO) << "Enabling playback on the default voice channel";
|
||||||
|
SetPlayout(audio_channel(), true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RtcVoiceMediaChannel::GetActiveStreams(cricket::AudioInfo::StreamList* actives) {
|
||||||
|
actives->clear();
|
||||||
|
for (ChannelMap::iterator it = mux_channels_.begin();
|
||||||
|
it != mux_channels_.end(); ++it) {
|
||||||
|
int level = GetOutputLevel(it->second);
|
||||||
|
if (level > 0) {
|
||||||
|
actives->push_back(std::make_pair(it->first, level));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int RtcVoiceMediaChannel::GetOutputLevel() {
|
||||||
|
// return the highest output level of all streams
|
||||||
|
int highest = GetOutputLevel(audio_channel());
|
||||||
|
for (ChannelMap::iterator it = mux_channels_.begin();
|
||||||
|
it != mux_channels_.end(); ++it) {
|
||||||
|
int level = GetOutputLevel(it->second);
|
||||||
|
highest = talk_base::_max(level, highest);
|
||||||
|
}
|
||||||
|
return highest;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RtcVoiceMediaChannel::SetRingbackTone(const char *buf, int len) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RtcVoiceMediaChannel::PlayRingbackTone(uint32 ssrc, bool play, bool loop) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RtcVoiceMediaChannel::PlayRingbackTone(bool play, bool loop) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RtcVoiceMediaChannel::PressDTMF(int event, bool playout) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RtcVoiceMediaChannel::OnPacketReceived(talk_base::Buffer* packet) {
|
||||||
|
// Pick which channel to send this packet to. If this packet doesn't match
|
||||||
|
// any multiplexed streams, just send it to the default channel. Otherwise,
|
||||||
|
// send it to the specific decoder instance for that stream.
|
||||||
|
int which_channel = GetChannel(
|
||||||
|
ParseSsrc(packet->data(), packet->length(), false));
|
||||||
|
if (which_channel == -1) {
|
||||||
|
which_channel = audio_channel();
|
||||||
|
}
|
||||||
|
|
||||||
|
engine()->webrtc()->network()->ReceivedRTPPacket(which_channel,
|
||||||
|
packet->data(),
|
||||||
|
packet->length());
|
||||||
|
}
|
||||||
|
|
||||||
|
void RtcVoiceMediaChannel::OnRtcpReceived(talk_base::Buffer* packet) {
|
||||||
|
// See above.
|
||||||
|
int which_channel = GetChannel(
|
||||||
|
ParseSsrc(packet->data(), packet->length(), true));
|
||||||
|
if (which_channel == -1) {
|
||||||
|
which_channel = audio_channel();
|
||||||
|
}
|
||||||
|
|
||||||
|
engine()->webrtc()->network()->ReceivedRTCPPacket(which_channel,
|
||||||
|
packet->data(),
|
||||||
|
packet->length());
|
||||||
|
}
|
||||||
|
|
||||||
|
void RtcVoiceMediaChannel::SetSendSsrc(uint32 ssrc) {
|
||||||
|
if (engine()->webrtc()->rtp()->SetLocalSSRC(audio_channel(), ssrc)
|
||||||
|
== -1) {
|
||||||
|
LOG_RTCERR2(SetSendSSRC, audio_channel(), ssrc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RtcVoiceMediaChannel::SetRtcpCName(const std::string& cname) {
|
||||||
|
if (engine()->webrtc()->rtp()->SetRTCP_CNAME(audio_channel(),
|
||||||
|
cname.c_str()) == -1) {
|
||||||
|
LOG_RTCERR2(SetRTCP_CNAME, audio_channel(), cname);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RtcVoiceMediaChannel::Mute(bool muted) {
|
||||||
|
if (engine()->webrtc()->volume()->SetInputMute(audio_channel(),
|
||||||
|
muted) == -1) {
|
||||||
|
LOG_RTCERR2(SetInputMute, audio_channel(), muted);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RtcVoiceMediaChannel::GetStats(cricket::VoiceMediaInfo* info) {
|
||||||
|
CallStatistics cs;
|
||||||
|
unsigned int ssrc;
|
||||||
|
CodecInst codec;
|
||||||
|
unsigned int level;
|
||||||
|
|
||||||
|
// Fill in the sender info, based on what we know, and what the
|
||||||
|
// remote side told us it got from its RTCP report.
|
||||||
|
cricket::VoiceSenderInfo sinfo;
|
||||||
|
memset(&sinfo, 0, sizeof(sinfo));
|
||||||
|
|
||||||
|
// Data we obtain locally.
|
||||||
|
memset(&cs, 0, sizeof(cs));
|
||||||
|
if (engine()->webrtc()->rtp()->GetRTCPStatistics(
|
||||||
|
audio_channel(), cs) == -1 ||
|
||||||
|
engine()->webrtc()->rtp()->GetLocalSSRC(audio_channel(), ssrc) == -1)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
sinfo.ssrc = ssrc;
|
||||||
|
sinfo.bytes_sent = cs.bytesSent;
|
||||||
|
sinfo.packets_sent = cs.packetsSent;
|
||||||
|
// RTT isn't known until a RTCP report is received. Until then, WebRTC
|
||||||
|
// returns 0 to indicate an error value.
|
||||||
|
sinfo.rtt_ms = (cs.rttMs > 0) ? cs.rttMs : -1;
|
||||||
|
|
||||||
|
// Data from the last remote RTCP report.
|
||||||
|
unsigned int ntp_high, ntp_low, timestamp, ptimestamp, jitter;
|
||||||
|
unsigned short loss; // NOLINT
|
||||||
|
if (engine()->webrtc()->rtp()->GetRemoteRTCPData(audio_channel(),
|
||||||
|
ntp_high, ntp_low, timestamp, ptimestamp, &jitter, &loss) != -1 &&
|
||||||
|
engine()->webrtc()->codec()->GetSendCodec(audio_channel(),
|
||||||
|
codec) != -1) {
|
||||||
|
// Convert Q8 to floating point.
|
||||||
|
sinfo.fraction_lost = static_cast<float>(loss) / (1 << 8);
|
||||||
|
// Convert samples to milliseconds.
|
||||||
|
if (codec.plfreq / 1000 > 0) {
|
||||||
|
sinfo.jitter_ms = jitter / (codec.plfreq / 1000);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sinfo.fraction_lost = -1;
|
||||||
|
sinfo.jitter_ms = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
sinfo.packets_lost = -1;
|
||||||
|
sinfo.ext_seqnum = -1;
|
||||||
|
|
||||||
|
// Local speech level.
|
||||||
|
sinfo.audio_level = (engine()->webrtc()->volume()->
|
||||||
|
GetSpeechInputLevelFullRange(level) != -1) ? level : -1;
|
||||||
|
info->senders.push_back(sinfo);
|
||||||
|
|
||||||
|
// Build the list of receivers, one for each mux channel, or 1 in a 1:1 call.
|
||||||
|
std::vector<int> channels;
|
||||||
|
for (ChannelMap::const_iterator it = mux_channels_.begin();
|
||||||
|
it != mux_channels_.end(); ++it) {
|
||||||
|
channels.push_back(it->second);
|
||||||
|
}
|
||||||
|
if (channels.empty()) {
|
||||||
|
channels.push_back(audio_channel());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the SSRC and stats for each receiver, based on our own calculations.
|
||||||
|
for (std::vector<int>::const_iterator it = channels.begin();
|
||||||
|
it != channels.end(); ++it) {
|
||||||
|
memset(&cs, 0, sizeof(cs));
|
||||||
|
if (engine()->webrtc()->rtp()->GetRemoteSSRC(*it, ssrc) != -1 &&
|
||||||
|
engine()->webrtc()->rtp()->GetRTCPStatistics(*it, cs) != -1 &&
|
||||||
|
engine()->webrtc()->codec()->GetRecCodec(*it, codec) != -1) {
|
||||||
|
cricket::VoiceReceiverInfo rinfo;
|
||||||
|
memset(&rinfo, 0, sizeof(rinfo));
|
||||||
|
rinfo.ssrc = ssrc;
|
||||||
|
rinfo.bytes_rcvd = cs.bytesReceived;
|
||||||
|
rinfo.packets_rcvd = cs.packetsReceived;
|
||||||
|
// The next four fields are from the most recently sent RTCP report.
|
||||||
|
// Convert Q8 to floating point.
|
||||||
|
rinfo.fraction_lost = static_cast<float>(cs.fractionLost) / (1 << 8);
|
||||||
|
rinfo.packets_lost = cs.cumulativeLost;
|
||||||
|
rinfo.ext_seqnum = cs.extendedMax;
|
||||||
|
// Convert samples to milliseconds.
|
||||||
|
if (codec.plfreq / 1000 > 0) {
|
||||||
|
rinfo.jitter_ms = cs.jitterSamples / (codec.plfreq / 1000);
|
||||||
|
}
|
||||||
|
// Get speech level.
|
||||||
|
rinfo.audio_level = (engine()->webrtc()->volume()->
|
||||||
|
GetSpeechOutputLevelFullRange(*it, level) != -1) ? level : -1;
|
||||||
|
info->receivers.push_back(rinfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RtcVoiceMediaChannel::GetLastMediaError(
|
||||||
|
uint32* ssrc, VoiceMediaChannel::Error* error) {
|
||||||
|
ASSERT(ssrc != NULL);
|
||||||
|
ASSERT(error != NULL);
|
||||||
|
FindSsrc(audio_channel(), ssrc);
|
||||||
|
*error = WebRTCErrorToChannelError(GetLastRtcError());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RtcVoiceMediaChannel::FindSsrc(int channel_num, uint32* ssrc) {
|
||||||
|
talk_base::CritScope lock(&mux_channels_cs_);
|
||||||
|
ASSERT(ssrc != NULL);
|
||||||
|
if (channel_num == audio_channel()) {
|
||||||
|
unsigned local_ssrc = 0;
|
||||||
|
// This is a sending channel.
|
||||||
|
if (engine()->webrtc()->rtp()->GetLocalSSRC(
|
||||||
|
channel_num, local_ssrc) != -1) {
|
||||||
|
*ssrc = local_ssrc;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
// Check whether this is a receiving channel.
|
||||||
|
for (ChannelMap::const_iterator it = mux_channels_.begin();
|
||||||
|
it != mux_channels_.end(); ++it) {
|
||||||
|
if (it->second == channel_num) {
|
||||||
|
*ssrc = it->first;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RtcVoiceMediaChannel::OnError(uint32 ssrc, int error) {
|
||||||
|
SignalMediaError(ssrc, WebRTCErrorToChannelError(error));
|
||||||
|
}
|
||||||
|
|
||||||
|
int RtcVoiceMediaChannel::GetChannel(uint32 ssrc) {
|
||||||
|
ChannelMap::iterator it = mux_channels_.find(ssrc);
|
||||||
|
return (it != mux_channels_.end()) ? it->second : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int RtcVoiceMediaChannel::GetOutputLevel(int channel) {
|
||||||
|
unsigned int ulevel;
|
||||||
|
int ret =
|
||||||
|
engine()->webrtc()->volume()->GetSpeechOutputLevel(channel, ulevel);
|
||||||
|
return (ret == 0) ? static_cast<int>(ulevel) : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RtcVoiceMediaChannel::EnableRtcp(int channel) {
|
||||||
|
if (engine()->webrtc()->rtp()->SetRTCPStatus(channel, true) == -1) {
|
||||||
|
LOG_RTCERR2(SetRTCPStatus, audio_channel(), 1);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RtcVoiceMediaChannel::SetPlayout(int channel, bool playout) {
|
||||||
|
if (playout) {
|
||||||
|
LOG(INFO) << "Starting playout for channel #" << channel;
|
||||||
|
if (engine()->webrtc()->base()->StartPlayout(channel) == -1) {
|
||||||
|
LOG_RTCERR1(StartPlayout, channel);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LOG(INFO) << "Stopping playout for channel #" << channel;
|
||||||
|
engine()->webrtc()->base()->StopPlayout(channel);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 RtcVoiceMediaChannel::ParseSsrc(const void* data, size_t len,
|
||||||
|
bool rtcp) {
|
||||||
|
size_t ssrc_pos = (!rtcp) ? 8 : 4;
|
||||||
|
uint32 ssrc = 0;
|
||||||
|
if (len >= (ssrc_pos + sizeof(ssrc))) {
|
||||||
|
ssrc = talk_base::GetBE32(static_cast<const char*>(data) + ssrc_pos);
|
||||||
|
}
|
||||||
|
return ssrc;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert WebRTC error code into VoiceMediaChannel::Error enum.
|
||||||
|
cricket::VoiceMediaChannel::Error RtcVoiceMediaChannel::WebRTCErrorToChannelError(
|
||||||
|
int err_code) {
|
||||||
|
switch (err_code) {
|
||||||
|
case 0:
|
||||||
|
return ERROR_NONE;
|
||||||
|
case VE_CANNOT_START_RECORDING:
|
||||||
|
case VE_MIC_VOL_ERROR:
|
||||||
|
case VE_GET_MIC_VOL_ERROR:
|
||||||
|
case VE_CANNOT_ACCESS_MIC_VOL:
|
||||||
|
return ERROR_REC_DEVICE_OPEN_FAILED;
|
||||||
|
case VE_SATURATION_WARNING:
|
||||||
|
return ERROR_REC_DEVICE_SATURATION;
|
||||||
|
case VE_REC_DEVICE_REMOVED:
|
||||||
|
return ERROR_REC_DEVICE_REMOVED;
|
||||||
|
case VE_RUNTIME_REC_WARNING:
|
||||||
|
case VE_RUNTIME_REC_ERROR:
|
||||||
|
return ERROR_REC_RUNTIME_ERROR;
|
||||||
|
case VE_CANNOT_START_PLAYOUT:
|
||||||
|
case VE_SPEAKER_VOL_ERROR:
|
||||||
|
case VE_GET_SPEAKER_VOL_ERROR:
|
||||||
|
case VE_CANNOT_ACCESS_SPEAKER_VOL:
|
||||||
|
return ERROR_PLAY_DEVICE_OPEN_FAILED;
|
||||||
|
case VE_RUNTIME_PLAY_WARNING:
|
||||||
|
case VE_RUNTIME_PLAY_ERROR:
|
||||||
|
return ERROR_PLAY_RUNTIME_ERROR;
|
||||||
|
default:
|
||||||
|
return VoiceMediaChannel::ERROR_OTHER;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace webrtc
|
||||||
|
|
||||||
244
third_party_mods/libjingle/source/talk/app/voicemediaengine.h
Normal file
244
third_party_mods/libjingle/source/talk/app/voicemediaengine.h
Normal file
@ -0,0 +1,244 @@
|
|||||||
|
/*
|
||||||
|
* libjingle
|
||||||
|
* Copyright 2004--2011, Google Inc.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
* 3. The name of the author may not be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||||
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||||
|
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||||
|
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||||
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||||
|
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||||
|
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TALK_APP_WEBRTC_AUDIOMEDIAENGINE_H_
|
||||||
|
#define TALK_APP_WEBRTC_AUDIOMEDIAENGINE_H_
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "talk/base/buffer.h"
|
||||||
|
#include "talk/base/byteorder.h"
|
||||||
|
#include "talk/base/logging.h"
|
||||||
|
#include "talk/base/scoped_ptr.h"
|
||||||
|
#include "talk/base/stream.h"
|
||||||
|
#include "talk/session/phone/channel.h"
|
||||||
|
#include "talk/session/phone/mediaengine.h"
|
||||||
|
#include "talk/session/phone/rtputils.h"
|
||||||
|
#include "talk/app/voiceengine.h"
|
||||||
|
|
||||||
|
namespace cricket {
|
||||||
|
class SoundclipMedia;
|
||||||
|
class VoiceMediaChannel;
|
||||||
|
}
|
||||||
|
namespace webrtc {
|
||||||
|
|
||||||
|
// MonitorStream is used to monitor a stream coming from WebRTC.
|
||||||
|
// For now we just dump the data.
|
||||||
|
class MonitorStream : public OutStream {
|
||||||
|
virtual bool Write(const void *buf, int len) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class AudioDeviceModule;
|
||||||
|
class RtcVoiceMediaChannel;
|
||||||
|
|
||||||
|
// RtcVoiceEngine is a class to be used with CompositeMediaEngine.
|
||||||
|
// It uses the WebRTC VoiceEngine library for audio handling.
|
||||||
|
class RtcVoiceEngine
|
||||||
|
: public VoiceEngineObserver,
|
||||||
|
public TraceCallback {
|
||||||
|
public:
|
||||||
|
RtcVoiceEngine(); // NOLINT
|
||||||
|
// Dependency injection for testing.
|
||||||
|
explicit RtcVoiceEngine(RtcWrapper* rtc_wrapper);
|
||||||
|
~RtcVoiceEngine();
|
||||||
|
bool Init();
|
||||||
|
void Terminate();
|
||||||
|
|
||||||
|
int GetCapabilities();
|
||||||
|
cricket::VoiceMediaChannel* CreateChannel();
|
||||||
|
cricket::SoundclipMedia* CreateSoundclip() { return NULL; }
|
||||||
|
bool SetDevices(const cricket::Device* in_device,
|
||||||
|
const cricket::Device* out_device);
|
||||||
|
bool SetOptions(int options);
|
||||||
|
bool GetOutputVolume(int* level);
|
||||||
|
bool SetOutputVolume(int level);
|
||||||
|
int GetInputLevel();
|
||||||
|
bool SetLocalMonitor(bool enable);
|
||||||
|
|
||||||
|
const std::vector<cricket::AudioCodec>& codecs();
|
||||||
|
bool FindCodec(const cricket::AudioCodec& codec);
|
||||||
|
bool FindRtcCodec(const cricket::AudioCodec& codec, CodecInst* gcodec);
|
||||||
|
|
||||||
|
void SetLogging(int min_sev, const char* filter);
|
||||||
|
|
||||||
|
// For tracking WebRTC channels. Needed because we have to pause them
|
||||||
|
// all when switching devices.
|
||||||
|
// May only be called by RtcVoiceMediaChannel.
|
||||||
|
void RegisterChannel(RtcVoiceMediaChannel *channel);
|
||||||
|
void UnregisterChannel(RtcVoiceMediaChannel *channel);
|
||||||
|
|
||||||
|
RtcWrapper* webrtc() { return rtc_wrapper_.get(); }
|
||||||
|
int GetLastRtcError();
|
||||||
|
|
||||||
|
private:
|
||||||
|
typedef std::vector<RtcVoiceMediaChannel *> ChannelList;
|
||||||
|
|
||||||
|
struct CodecPref {
|
||||||
|
const char* name;
|
||||||
|
int clockrate;
|
||||||
|
};
|
||||||
|
|
||||||
|
void Construct();
|
||||||
|
bool InitInternal();
|
||||||
|
void ApplyLogging();
|
||||||
|
virtual void Print(const TraceLevel level,
|
||||||
|
const char* traceString, const int length);
|
||||||
|
virtual void CallbackOnError(const int errCode, const int channel);
|
||||||
|
static int GetCodecPreference(const char *name, int clockrate);
|
||||||
|
// Given the device type, name, and id, find WebRTC's device id. Return true and
|
||||||
|
// set the output parameter rtc_id if successful.
|
||||||
|
bool FindAudioDeviceId(
|
||||||
|
bool is_input, const std::string& dev_name, int dev_id, int* rtc_id);
|
||||||
|
bool FindChannelAndSsrc(int channel_num,
|
||||||
|
RtcVoiceMediaChannel** channel,
|
||||||
|
uint32* ssrc) const;
|
||||||
|
|
||||||
|
static const int kDefaultLogSeverity = talk_base::LS_WARNING;
|
||||||
|
static const CodecPref kCodecPrefs[];
|
||||||
|
|
||||||
|
// The primary instance of WebRTC VoiceEngine.
|
||||||
|
talk_base::scoped_ptr<RtcWrapper> rtc_wrapper_;
|
||||||
|
int log_level_;
|
||||||
|
std::vector<cricket::AudioCodec> codecs_;
|
||||||
|
talk_base::scoped_ptr<MonitorStream> monitor_;
|
||||||
|
// TODO: Can't use scoped_ptr here since ~AudioDeviceModule is protected.
|
||||||
|
AudioDeviceModule* adm_;
|
||||||
|
ChannelList channels_;
|
||||||
|
talk_base::CriticalSection channels_cs_;
|
||||||
|
};
|
||||||
|
|
||||||
|
// RtcMediaChannel is a class that implements the common WebRTC channel
|
||||||
|
// functionality.
|
||||||
|
template <class T, class E>
|
||||||
|
class RtcMediaChannel : public T, public Transport {
|
||||||
|
public:
|
||||||
|
RtcMediaChannel(E *engine, int channel)
|
||||||
|
: engine_(engine), audio_channel_(channel), sequence_number_(-1) {}
|
||||||
|
E *engine() { return engine_; }
|
||||||
|
int audio_channel() const { return audio_channel_; }
|
||||||
|
bool valid() const { return audio_channel_ != -1; }
|
||||||
|
protected:
|
||||||
|
// implements Transport interface
|
||||||
|
virtual int SendPacket(int channel, const void *data, int len) {
|
||||||
|
if (!T::network_interface_) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint8* header = static_cast<const uint8*>(data);
|
||||||
|
sequence_number_ = talk_base::GetBE16(header + 2);
|
||||||
|
|
||||||
|
talk_base::Buffer packet(data, len, cricket::kMaxRtpPacketLen);
|
||||||
|
return T::network_interface_->SendPacket(&packet) ? len : -1;
|
||||||
|
}
|
||||||
|
virtual int SendRTCPPacket(int channel, const void *data, int len) {
|
||||||
|
if (!T::network_interface_) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
talk_base::Buffer packet(data, len, cricket::kMaxRtpPacketLen);
|
||||||
|
return T::network_interface_->SendRtcp(&packet) ? len : -1;
|
||||||
|
}
|
||||||
|
int sequence_number() {
|
||||||
|
return sequence_number_;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
E *engine_;
|
||||||
|
int audio_channel_;
|
||||||
|
int sequence_number_;
|
||||||
|
};
|
||||||
|
|
||||||
|
// RtcVoiceMediaChannel is an implementation of VoiceMediaChannel that uses
|
||||||
|
// WebRTC Voice Engine.
|
||||||
|
class RtcVoiceMediaChannel
|
||||||
|
: public RtcMediaChannel<cricket::VoiceMediaChannel, RtcVoiceEngine> {
|
||||||
|
public:
|
||||||
|
explicit RtcVoiceMediaChannel(RtcVoiceEngine *engine);
|
||||||
|
virtual ~RtcVoiceMediaChannel();
|
||||||
|
virtual bool SetOptions(int options);
|
||||||
|
virtual bool SetRecvCodecs(const std::vector<cricket::AudioCodec> &codecs);
|
||||||
|
virtual bool SetSendCodecs(const std::vector<cricket::AudioCodec> &codecs);
|
||||||
|
virtual bool SetPlayout(bool playout);
|
||||||
|
bool GetPlayout();
|
||||||
|
virtual bool SetSend(cricket::SendFlags send);
|
||||||
|
cricket::SendFlags GetSend();
|
||||||
|
virtual bool AddStream(uint32 ssrc);
|
||||||
|
virtual bool RemoveStream(uint32 ssrc);
|
||||||
|
virtual bool GetActiveStreams(cricket::AudioInfo::StreamList* actives);
|
||||||
|
virtual int GetOutputLevel();
|
||||||
|
|
||||||
|
virtual bool SetRingbackTone(const char *buf, int len);
|
||||||
|
virtual bool PlayRingbackTone(uint32 ssrc, bool play, bool loop);
|
||||||
|
virtual bool PlayRingbackTone(bool play, bool loop);
|
||||||
|
virtual bool PressDTMF(int event, bool playout);
|
||||||
|
|
||||||
|
virtual void OnPacketReceived(talk_base::Buffer* packet);
|
||||||
|
virtual void OnRtcpReceived(talk_base::Buffer* packet);
|
||||||
|
virtual void SetSendSsrc(uint32 id);
|
||||||
|
virtual bool SetRtcpCName(const std::string& cname);
|
||||||
|
virtual bool Mute(bool mute);
|
||||||
|
virtual bool SetRecvRtpHeaderExtensions(
|
||||||
|
const std::vector<cricket::RtpHeaderExtension>& extensions) { return false; }
|
||||||
|
virtual bool SetSendRtpHeaderExtensions(
|
||||||
|
const std::vector<cricket::RtpHeaderExtension>& extensions) { return false; }
|
||||||
|
virtual bool SetSendBandwidth(bool autobw, int bps) { return false; }
|
||||||
|
virtual bool GetStats(cricket::VoiceMediaInfo* info);
|
||||||
|
|
||||||
|
virtual void GetLastMediaError(uint32* ssrc,
|
||||||
|
VoiceMediaChannel::Error* error);
|
||||||
|
bool FindSsrc(int channel_num, uint32* ssrc);
|
||||||
|
void OnError(uint32 ssrc, int error);
|
||||||
|
virtual int GetMediaChannelId() { return audio_channel(); }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
int GetLastRtcError() { return engine()->GetLastRtcError(); }
|
||||||
|
int GetChannel(uint32 ssrc);
|
||||||
|
int GetOutputLevel(int channel);
|
||||||
|
bool EnableRtcp(int channel);
|
||||||
|
bool SetPlayout(int channel, bool playout);
|
||||||
|
static uint32 ParseSsrc(const void* data, size_t len, bool rtcp);
|
||||||
|
static Error WebRTCErrorToChannelError(int err_code);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
typedef std::map<uint32, int> ChannelMap;
|
||||||
|
int channel_options_;
|
||||||
|
bool playout_;
|
||||||
|
cricket::SendFlags send_;
|
||||||
|
ChannelMap mux_channels_; // for multiple sources
|
||||||
|
// mux_channels_ can be read from WebRTC callback thread. Accesses off the
|
||||||
|
// WebRTC thread must be synchronized with edits on the worker thread. Reads
|
||||||
|
// on the worker thread are ok.
|
||||||
|
mutable talk_base::CriticalSection mux_channels_cs_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace webrtc
|
||||||
|
|
||||||
|
#endif // TALK_APP_WEBRTC_AUDIOMEDIAENGINE_H_
|
||||||
434
third_party_mods/libjingle/source/talk/app/webrtc_json.cc
Normal file
434
third_party_mods/libjingle/source/talk/app/webrtc_json.cc
Normal file
@ -0,0 +1,434 @@
|
|||||||
|
/*
|
||||||
|
* libjingle
|
||||||
|
* Copyright 2004--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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
//this file contains all the json helper methods
|
||||||
|
#include "talk/app/webrtc_json.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "talk/base/json.h"
|
||||||
|
#include "talk/base/logging.h"
|
||||||
|
#include "talk/session/phone/mediasessionclient.h"
|
||||||
|
#include "talk/session/phone/codec.h"
|
||||||
|
#include "json/json.h"
|
||||||
|
|
||||||
|
namespace webrtc {
|
||||||
|
|
||||||
|
static const int kIceComponent = 1;
|
||||||
|
static const int kIceFoundation = 1;
|
||||||
|
|
||||||
|
bool GetConnectionMediator(const Json::Value& value, std::string& connectionMediator) {
|
||||||
|
if (value.type() != Json::objectValue && value.type() != Json::nullValue) {
|
||||||
|
LOG(LS_WARNING) << "Failed to parse stun values" ;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!GetStringFromJsonObject(value, "connectionmediator", &connectionMediator)) {
|
||||||
|
LOG(LS_WARNING) << "Failed to parse JSON for value: "
|
||||||
|
<< value.toStyledString();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GetStunServer(const Json::Value& value, StunServiceDetails& stunServer) {
|
||||||
|
if (value.type() != Json::objectValue && value.type() != Json::nullValue) {
|
||||||
|
LOG(LS_WARNING) << "Failed to parse stun values" ;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Json::Value stun;
|
||||||
|
if (GetValueFromJsonObject(value, "stun_service", &stun)) {
|
||||||
|
if (stun.type() == Json::objectValue) {
|
||||||
|
if (!GetStringFromJsonObject(stun, "host", &stunServer.host) ||
|
||||||
|
!GetStringFromJsonObject(stun, "service", &stunServer.service) ||
|
||||||
|
!GetStringFromJsonObject(stun, "protocol", &stunServer.protocol)) {
|
||||||
|
LOG(LS_WARNING) << "Failed to parse JSON value: "
|
||||||
|
<< value.toStyledString();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}
|
||||||
|
bool GetTurnServer(const Json::Value& value, std::string& turnServer) {
|
||||||
|
if (value.type() != Json::objectValue && value.type() != Json::nullValue) {
|
||||||
|
LOG(LS_WARNING) << "Failed to parse stun values" ;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Json::Value turn;
|
||||||
|
if (GetValueFromJsonObject(value, "turn_service", &turn)) {
|
||||||
|
if (turn.type() == Json::objectValue) {
|
||||||
|
if (!GetStringFromJsonObject(turn, "host", &turnServer)) {
|
||||||
|
LOG(LS_WARNING) << "Failed to parse JSON value: "
|
||||||
|
<< value.toStyledString();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GetJSONSignalingMessage(
|
||||||
|
const cricket::SessionDescription* sdp,
|
||||||
|
const std::vector<cricket::Candidate>& candidates,
|
||||||
|
std::string* signaling_message) {
|
||||||
|
const cricket::ContentInfo* audio_content = GetFirstAudioContent(sdp);
|
||||||
|
const cricket::ContentInfo* video_content = GetFirstVideoContent(sdp);
|
||||||
|
|
||||||
|
std::vector<Json::Value> media;
|
||||||
|
if (audio_content) {
|
||||||
|
Json::Value value;
|
||||||
|
BuildMediaMessage(audio_content, candidates, false, value);
|
||||||
|
media.push_back(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (video_content) {
|
||||||
|
Json::Value value;
|
||||||
|
BuildMediaMessage(video_content, candidates, true, value);
|
||||||
|
media.push_back(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
Json::Value signal;
|
||||||
|
Append(signal, "media", media);
|
||||||
|
|
||||||
|
// now serialize
|
||||||
|
*signaling_message = Serialize(signal);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BuildMediaMessage(
|
||||||
|
const cricket::ContentInfo* content_info,
|
||||||
|
const std::vector<cricket::Candidate>& candidates,
|
||||||
|
bool video,
|
||||||
|
Json::Value& params) {
|
||||||
|
|
||||||
|
if (!content_info) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (video) {
|
||||||
|
Append(params, "label", 2); //always video 2
|
||||||
|
} else {
|
||||||
|
Append(params, "label", 1); //always audio 1
|
||||||
|
}
|
||||||
|
std::vector<Json::Value> rtpmap;
|
||||||
|
|
||||||
|
if (!BuildRtpMapParams(content_info, video, rtpmap)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Append(params, "rtpmap", rtpmap);
|
||||||
|
|
||||||
|
Json::Value attributes;
|
||||||
|
// Append(attributes, "ice-pwd", candidates.front().password());
|
||||||
|
// Append(attributes, "ice-ufrag", candidates.front().username());
|
||||||
|
std::vector<Json::Value> jcandidates;
|
||||||
|
|
||||||
|
if (!BuildAttributes(candidates, video, jcandidates)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Append(attributes, "candidate", jcandidates);
|
||||||
|
Append(params, "attributes", attributes);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BuildRtpMapParams(const cricket::ContentInfo* content_info,
|
||||||
|
bool video,
|
||||||
|
std::vector<Json::Value>& rtpmap) {
|
||||||
|
|
||||||
|
if (!video) {
|
||||||
|
const cricket::AudioContentDescription* audio_offer =
|
||||||
|
static_cast<const cricket::AudioContentDescription*>(
|
||||||
|
content_info->description);
|
||||||
|
|
||||||
|
|
||||||
|
for (std::vector<cricket::AudioCodec>::const_iterator iter =
|
||||||
|
audio_offer->codecs().begin();
|
||||||
|
iter != audio_offer->codecs().end(); ++iter) {
|
||||||
|
|
||||||
|
Json::Value codec;
|
||||||
|
std::string codec_str = std::string("audio/").append(iter->name);
|
||||||
|
Append(codec, "codec", codec_str);
|
||||||
|
Json::Value codec_id;
|
||||||
|
Append(codec_id, talk_base::ToString(iter->id), codec);
|
||||||
|
rtpmap.push_back(codec_id);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const cricket::VideoContentDescription* video_offer =
|
||||||
|
static_cast<const cricket::VideoContentDescription*>(
|
||||||
|
content_info->description);
|
||||||
|
|
||||||
|
|
||||||
|
for (std::vector<cricket::VideoCodec>::const_iterator iter =
|
||||||
|
video_offer->codecs().begin();
|
||||||
|
iter != video_offer->codecs().end(); ++iter) {
|
||||||
|
|
||||||
|
Json::Value codec;
|
||||||
|
std::string codec_str = std::string("video/").append(iter->name);
|
||||||
|
Append(codec, "codec", codec_str);
|
||||||
|
Json::Value codec_id;
|
||||||
|
Append(codec_id, talk_base::ToString(iter->id), codec);
|
||||||
|
rtpmap.push_back(codec_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BuildAttributes(const std::vector<cricket::Candidate>& candidates,
|
||||||
|
bool video,
|
||||||
|
std::vector<Json::Value>& jcandidates) {
|
||||||
|
|
||||||
|
for (std::vector<cricket::Candidate>::const_iterator iter =
|
||||||
|
candidates.begin(); iter != candidates.end(); ++iter) {
|
||||||
|
if ((video && !iter->name().compare("video_rtp") ||
|
||||||
|
(!video && !iter->name().compare("rtp")))) {
|
||||||
|
Json::Value candidate;
|
||||||
|
Append(candidate, "component", kIceComponent);
|
||||||
|
Append(candidate, "foundation", kIceFoundation);
|
||||||
|
Append(candidate, "generation", iter->generation());
|
||||||
|
Append(candidate, "proto", iter->protocol());
|
||||||
|
Append(candidate, "priority", iter->preference());
|
||||||
|
Append(candidate, "ip", iter->address().IPAsString());
|
||||||
|
Append(candidate, "port", iter->address().PortAsString());
|
||||||
|
Append(candidate, "type", iter->type());
|
||||||
|
Append(candidate, "name", iter->name());
|
||||||
|
Append(candidate, "network_name", iter->network_name());
|
||||||
|
Append(candidate, "username", iter->username());
|
||||||
|
Append(candidate, "password", iter->password());
|
||||||
|
jcandidates.push_back(candidate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Serialize(const Json::Value& value) {
|
||||||
|
Json::StyledWriter writer;
|
||||||
|
return writer.write(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Deserialize(const std::string& message, Json::Value& value) {
|
||||||
|
Json::Reader reader;
|
||||||
|
return reader.parse(message, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool ParseJSONSignalingMessage(const std::string& signaling_message,
|
||||||
|
cricket::SessionDescription*& sdp,
|
||||||
|
std::vector<cricket::Candidate>& candidates) {
|
||||||
|
ASSERT(!sdp); // expect this to NULL
|
||||||
|
// first deserialize message
|
||||||
|
Json::Value value;
|
||||||
|
if (!Deserialize(signaling_message, value)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get media objects
|
||||||
|
std::vector<Json::Value> mlines = ReadValues(value, "media");
|
||||||
|
if (mlines.empty()) {
|
||||||
|
// no m-lines found
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
sdp = new cricket::SessionDescription();
|
||||||
|
|
||||||
|
// get codec information
|
||||||
|
for (size_t i = 0; i < mlines.size(); ++i) {
|
||||||
|
if (mlines[i]["label"].asInt() == 1) {
|
||||||
|
cricket::AudioContentDescription* audio_content =
|
||||||
|
new cricket::AudioContentDescription();
|
||||||
|
ParseAudioCodec(mlines[i], audio_content);
|
||||||
|
audio_content->SortCodecs();
|
||||||
|
sdp->AddContent(cricket::CN_AUDIO, cricket::NS_JINGLE_RTP, audio_content);
|
||||||
|
ParseICECandidates(mlines[i], candidates);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
cricket::VideoContentDescription* video_content =
|
||||||
|
new cricket::VideoContentDescription();
|
||||||
|
ParseVideoCodec(mlines[i], video_content);
|
||||||
|
video_content->SortCodecs();
|
||||||
|
sdp->AddContent(cricket::CN_VIDEO, cricket::NS_JINGLE_RTP, video_content);
|
||||||
|
ParseICECandidates(mlines[i], candidates);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ParseAudioCodec(Json::Value value,
|
||||||
|
cricket::AudioContentDescription* content) {
|
||||||
|
std::vector<Json::Value> rtpmap(ReadValues(value, "rtpmap"));
|
||||||
|
if (rtpmap.empty())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < rtpmap.size(); ++i) {
|
||||||
|
cricket::AudioCodec codec;
|
||||||
|
std::string pltype = rtpmap[i].begin().memberName();
|
||||||
|
talk_base::FromString(pltype, &codec.id);
|
||||||
|
Json::Value codec_info = rtpmap[i][pltype];
|
||||||
|
std::vector<std::string> tokens;
|
||||||
|
talk_base::split(codec_info["codec"].asString(), '/', &tokens);
|
||||||
|
codec.name = tokens[1];
|
||||||
|
content->AddCodec(codec);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ParseVideoCodec(Json::Value value,
|
||||||
|
cricket::VideoContentDescription* content) {
|
||||||
|
std::vector<Json::Value> rtpmap(ReadValues(value, "rtpmap"));
|
||||||
|
if (rtpmap.empty())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < rtpmap.size(); ++i) {
|
||||||
|
cricket::VideoCodec codec;
|
||||||
|
std::string pltype = rtpmap[i].begin().memberName();
|
||||||
|
talk_base::FromString(pltype, &codec.id);
|
||||||
|
Json::Value codec_info = rtpmap[i][pltype];
|
||||||
|
std::vector<std::string> tokens;
|
||||||
|
talk_base::split(codec_info["codec"].asString(), '/', &tokens);
|
||||||
|
codec.name = tokens[1];
|
||||||
|
content->AddCodec(codec);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ParseICECandidates(Json::Value& value,
|
||||||
|
std::vector<cricket::Candidate>& candidates) {
|
||||||
|
Json::Value attributes = ReadValue(value, "attributes");
|
||||||
|
std::string ice_pwd = ReadString(attributes, "ice-pwd");
|
||||||
|
std::string ice_ufrag = ReadString(attributes, "ice-ufrag");
|
||||||
|
|
||||||
|
std::vector<Json::Value> jcandidates = ReadValues(attributes, "candidate");
|
||||||
|
char buffer[64];
|
||||||
|
for (size_t i = 0; i < jcandidates.size(); ++i) {
|
||||||
|
cricket::Candidate cand;
|
||||||
|
std::string str;
|
||||||
|
str = ReadUInt(jcandidates[i], "generation");
|
||||||
|
cand.set_generation_str(str);
|
||||||
|
str = ReadString(jcandidates[i], "proto");
|
||||||
|
cand.set_protocol(str);
|
||||||
|
double priority = ReadDouble(jcandidates[i], "priority");
|
||||||
|
#ifdef _DEBUG
|
||||||
|
double as_int = static_cast<int>(priority);
|
||||||
|
ASSERT(as_int == priority);
|
||||||
|
#endif
|
||||||
|
sprintf(buffer, "%i", static_cast<int>(priority));
|
||||||
|
str = buffer;
|
||||||
|
cand.set_preference_str(str);
|
||||||
|
talk_base::SocketAddress addr;
|
||||||
|
str = ReadString(jcandidates[i], "ip");
|
||||||
|
addr.SetIP(str);
|
||||||
|
str = ReadString(jcandidates[i], "port");
|
||||||
|
int port; talk_base::FromString(str, &port);
|
||||||
|
addr.SetPort(port);
|
||||||
|
cand.set_address(addr);
|
||||||
|
str = ReadString(jcandidates[i], "type");
|
||||||
|
cand.set_type(str);
|
||||||
|
str = ReadString(jcandidates[i], "name");
|
||||||
|
cand.set_name(str);
|
||||||
|
str = ReadString(jcandidates[i], "network_name");
|
||||||
|
cand.set_network_name(str);
|
||||||
|
str = ReadString(jcandidates[i], "username");
|
||||||
|
cand.set_username(str);
|
||||||
|
str = ReadString(jcandidates[i], "password");
|
||||||
|
cand.set_password(str);
|
||||||
|
candidates.push_back(cand);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Json::Value> ReadValues(
|
||||||
|
Json::Value& value, const std::string& key) {
|
||||||
|
std::vector<Json::Value> objects;
|
||||||
|
for (size_t i = 0; i < value[key].size(); ++i) {
|
||||||
|
objects.push_back(value[key][i]);
|
||||||
|
}
|
||||||
|
return objects;
|
||||||
|
}
|
||||||
|
|
||||||
|
Json::Value ReadValue(Json::Value& value, const std::string& key) {
|
||||||
|
return value[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string ReadString(Json::Value& value, const std::string& key) {
|
||||||
|
return value[key].asString();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 ReadUInt(Json::Value& value, const std::string& key) {
|
||||||
|
return value[key].asUInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
double ReadDouble(Json::Value& value, const std::string& key) {
|
||||||
|
return value[key].asDouble();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add values
|
||||||
|
void Append(Json::Value& object, const std::string& key, bool value) {
|
||||||
|
object[key] = Json::Value(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Append(Json::Value& object, const std::string& key, char * value) {
|
||||||
|
object[key] = Json::Value(value);
|
||||||
|
}
|
||||||
|
void Append(Json::Value& object, const std::string& key, double value) {
|
||||||
|
object[key] = Json::Value(value);
|
||||||
|
}
|
||||||
|
void Append(Json::Value& object, const std::string& key, float value) {
|
||||||
|
object[key] = Json::Value(value);
|
||||||
|
}
|
||||||
|
void Append(Json::Value& object, const std::string& key, int value) {
|
||||||
|
object[key] = Json::Value(value);
|
||||||
|
}
|
||||||
|
void Append(Json::Value& object, const std::string& key, std::string value) {
|
||||||
|
object[key] = Json::Value(value);
|
||||||
|
}
|
||||||
|
void Append(Json::Value& object, const std::string& key, uint32 value) {
|
||||||
|
object[key] = Json::Value(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Append(Json::Value& object, const std::string& key, Json::Value value) {
|
||||||
|
object[key] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Append(Json::Value & object,
|
||||||
|
const std::string & key,
|
||||||
|
std::vector<Json::Value>& values){
|
||||||
|
for (std::vector<Json::Value>::const_iterator iter = values.begin();
|
||||||
|
iter != values.end(); ++iter) {
|
||||||
|
object[key].append(*iter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} //namespace webrtc
|
||||||
116
third_party_mods/libjingle/source/talk/app/webrtc_json.h
Normal file
116
third_party_mods/libjingle/source/talk/app/webrtc_json.h
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
/*
|
||||||
|
* libjingle
|
||||||
|
* Copyright 2004--2011, Google Inc.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
* 3. The name of the author may not be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||||
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||||
|
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||||
|
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||||
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||||
|
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||||
|
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TALK_APP_WEBRTC_WEBRTC_JSON_H_
|
||||||
|
#define TALK_APP_WEBRTC_WEBRTC_JSON_H_
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "json/json.h"
|
||||||
|
#include "talk/session/phone/codec.h"
|
||||||
|
#include "talk/p2p/base/candidate.h"
|
||||||
|
|
||||||
|
namespace Json {
|
||||||
|
class Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace cricket {
|
||||||
|
class AudioContentDescription;
|
||||||
|
class VideoContentDescription;
|
||||||
|
struct ContentInfo;
|
||||||
|
class SessionDescription;
|
||||||
|
}
|
||||||
|
struct StunServiceDetails {
|
||||||
|
std::string host;
|
||||||
|
std::string service;
|
||||||
|
std::string protocol;
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace webrtc {
|
||||||
|
|
||||||
|
bool GetConnectionMediator(const Json::Value& value,
|
||||||
|
std::string& connectionMediator);
|
||||||
|
bool GetStunServer(const Json::Value& value, StunServiceDetails& stun);
|
||||||
|
bool GetTurnServer(const Json::Value& value, std::string& turnServer);
|
||||||
|
bool FromJsonToAVCodec(const Json::Value& value,
|
||||||
|
cricket::AudioContentDescription* audio,
|
||||||
|
cricket::VideoContentDescription* video);
|
||||||
|
|
||||||
|
std::vector<Json::Value> ReadValues(Json::Value& value, const std::string& key);
|
||||||
|
|
||||||
|
bool BuildMediaMessage(
|
||||||
|
const cricket::ContentInfo* content_info,
|
||||||
|
const std::vector<cricket::Candidate>& candidates,
|
||||||
|
bool video,
|
||||||
|
Json::Value& value);
|
||||||
|
|
||||||
|
bool GetJSONSignalingMessage(
|
||||||
|
const cricket::SessionDescription* sdp,
|
||||||
|
const std::vector<cricket::Candidate>& candidates,
|
||||||
|
std::string* signaling_message);
|
||||||
|
|
||||||
|
bool BuildRtpMapParams(
|
||||||
|
const cricket::ContentInfo* audio_offer,
|
||||||
|
bool video,
|
||||||
|
std::vector<Json::Value>& rtpmap);
|
||||||
|
|
||||||
|
bool BuildAttributes(const std::vector<cricket::Candidate>& candidates,
|
||||||
|
bool video,
|
||||||
|
std::vector<Json::Value>& jcandidates);
|
||||||
|
|
||||||
|
std::string Serialize(const Json::Value& value);
|
||||||
|
bool Deserialize(const std::string& message, Json::Value& value);
|
||||||
|
|
||||||
|
bool ParseJSONSignalingMessage(const std::string& signaling_message,
|
||||||
|
cricket::SessionDescription*& sdp,
|
||||||
|
std::vector<cricket::Candidate>& candidates);
|
||||||
|
bool ParseAudioCodec(Json::Value value, cricket::AudioContentDescription* content);
|
||||||
|
bool ParseVideoCodec(Json::Value value, cricket::VideoContentDescription* content);
|
||||||
|
bool ParseICECandidates(Json::Value& value,
|
||||||
|
std::vector<cricket::Candidate>& candidates);
|
||||||
|
Json::Value ReadValue(Json::Value& value, const std::string& key);
|
||||||
|
std::string ReadString(Json::Value& value, const std::string& key);
|
||||||
|
double ReadDouble(Json::Value& value, const std::string& key);
|
||||||
|
uint32 ReadUInt(Json::Value& value, const std::string& key);
|
||||||
|
|
||||||
|
// Add values
|
||||||
|
void Append(Json::Value& object, const std::string& key, bool value);
|
||||||
|
|
||||||
|
void Append(Json::Value& object, const std::string& key, char * value);
|
||||||
|
void Append(Json::Value& object, const std::string& key, double value);
|
||||||
|
void Append(Json::Value& object, const std::string& key, float value);
|
||||||
|
void Append(Json::Value& object, const std::string& key, int value);
|
||||||
|
void Append(Json::Value& object, const std::string& key, std::string value);
|
||||||
|
void Append(Json::Value& object, const std::string& key, uint32 value);
|
||||||
|
void Append(Json::Value& object, const std::string& key, Json::Value value);
|
||||||
|
void Append(Json::Value & object,
|
||||||
|
const std::string & key,
|
||||||
|
std::vector<Json::Value>& values);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif // TALK_APP_WEBRTC_WEBRTC_JSON_H_
|
||||||
@ -0,0 +1,77 @@
|
|||||||
|
/*
|
||||||
|
* libjingle
|
||||||
|
* Copyright 2004--2011, Google Inc.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
* 3. The name of the author may not be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||||
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||||
|
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||||
|
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||||
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||||
|
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||||
|
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "talk/base/gunit.h"
|
||||||
|
#include "talk/app/webrtc_json.h"
|
||||||
|
|
||||||
|
namespace webrtc {
|
||||||
|
|
||||||
|
Json::Value JsonValueFromString(const std::string &json) {
|
||||||
|
Json::Reader reader;
|
||||||
|
Json::Value value;
|
||||||
|
|
||||||
|
EXPECT_TRUE(reader.parse(json, value, false));
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
class WebRTCJsonTest : public testing::Test {
|
||||||
|
public:
|
||||||
|
WebRTCJsonTest() {}
|
||||||
|
~WebRTCJsonTest() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_F(WebRTCJsonTest, TestParseConfig) {
|
||||||
|
Json::Value value(JsonValueFromString(
|
||||||
|
"\{"
|
||||||
|
" \"connectionmediator\": \"https://somewhere.example.com/conneg\","
|
||||||
|
" \"stun_service\": { "
|
||||||
|
" \"host\" : \"stun.service.example.com\","
|
||||||
|
" \"service\" : \"stun\","
|
||||||
|
" \"protocol\" : \"udp\""
|
||||||
|
" }"
|
||||||
|
" }"));
|
||||||
|
|
||||||
|
std::string c;
|
||||||
|
EXPECT_TRUE(GetConnectionMediator(value, c));
|
||||||
|
std::cout << " --- connectionmediator --- : " << c << std::endl;
|
||||||
|
|
||||||
|
StunServiceDetails stun;
|
||||||
|
EXPECT_TRUE(GetStunServer(value, stun));
|
||||||
|
std::cout << " --- stun host --- : " << stun.host << std::endl;
|
||||||
|
std::cout << " --- stun service --- : " << stun.service << std::endl;
|
||||||
|
std::cout << " --- stun protocol --- : " << stun.protocol << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(WebRTCJsonTest, TestLocalBlob) {
|
||||||
|
EXPECT_TRUE(FromSessionDescriptionToJson());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,137 @@
|
|||||||
|
// Copyright 2011 Google Inc. All Rights Reserved.
|
||||||
|
// Author: mallinath@google.com (Mallinath Bareddy)
|
||||||
|
|
||||||
|
#include "talk/app/webrtcchannelmanager.h"
|
||||||
|
|
||||||
|
namespace webrtc {
|
||||||
|
|
||||||
|
struct VideoCaptureDeviceParams : public talk_base::MessageData {
|
||||||
|
VideoCaptureDeviceParams(const std::string& cam_device)
|
||||||
|
: cam_device(cam_device),
|
||||||
|
result(false) {}
|
||||||
|
const std::string cam_device;
|
||||||
|
bool result;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct RenderParams : public talk_base::MessageData {
|
||||||
|
RenderParams(int channel_id,
|
||||||
|
void* window,
|
||||||
|
unsigned int zOrder,
|
||||||
|
float left,
|
||||||
|
float top,
|
||||||
|
float right,
|
||||||
|
float bottom)
|
||||||
|
:channel_id(channel_id)
|
||||||
|
,window(window)
|
||||||
|
,zOrder(zOrder)
|
||||||
|
,left(left)
|
||||||
|
,top(top)
|
||||||
|
,right(right)
|
||||||
|
,bottom(bottom) {}
|
||||||
|
|
||||||
|
int channel_id;
|
||||||
|
void* window;
|
||||||
|
unsigned int zOrder;
|
||||||
|
float left;
|
||||||
|
float top;
|
||||||
|
float right;
|
||||||
|
float bottom;
|
||||||
|
bool result;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool WebRtcChannelManager::Init() {
|
||||||
|
return MaybeInit();
|
||||||
|
}
|
||||||
|
|
||||||
|
cricket::VoiceChannel* WebRtcChannelManager::CreateVoiceChannel(
|
||||||
|
cricket::BaseSession* s, const std::string& content_name, bool rtcp) {
|
||||||
|
return (MaybeInit()) ?
|
||||||
|
ChannelManager::CreateVoiceChannel(s, content_name, rtcp) : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
cricket::VideoChannel* WebRtcChannelManager::CreateVideoChannel(
|
||||||
|
cricket::BaseSession* s, const std::string& content_name, bool rtcp,
|
||||||
|
cricket::VoiceChannel* vc) {
|
||||||
|
return (MaybeInit()) ?
|
||||||
|
ChannelManager::CreateVideoChannel(s, content_name, rtcp, vc) : NULL;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
cricket::Soundclip* WebRtcChannelManager::CreateSoundclip() {
|
||||||
|
return (MaybeInit()) ? ChannelManager::CreateSoundclip() : NULL;
|
||||||
|
}
|
||||||
|
void WebRtcChannelManager::DestroyVoiceChannel(cricket::VoiceChannel* vc) {
|
||||||
|
ChannelManager::DestroyVoiceChannel(vc);
|
||||||
|
MaybeTerm();
|
||||||
|
}
|
||||||
|
void WebRtcChannelManager::DestroyVideoChannel(cricket::VideoChannel* vc) {
|
||||||
|
ChannelManager::DestroyVideoChannel(vc);
|
||||||
|
MaybeTerm();
|
||||||
|
}
|
||||||
|
void WebRtcChannelManager::DestroySoundclip(cricket::Soundclip* s) {
|
||||||
|
ChannelManager::DestroySoundclip(s);
|
||||||
|
MaybeTerm();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WebRtcChannelManager::MaybeInit() {
|
||||||
|
bool ret = initialized();
|
||||||
|
if (!ret) {
|
||||||
|
ret = ChannelManager::Init();
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WebRtcChannelManager::MaybeTerm() {
|
||||||
|
if (initialized() && !has_channels()) {
|
||||||
|
Terminate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WebRtcChannelManager::SetVideoRenderer(int channel_id,
|
||||||
|
void* window,
|
||||||
|
unsigned int zOrder,
|
||||||
|
float left,
|
||||||
|
float top,
|
||||||
|
float right,
|
||||||
|
float bottom) {
|
||||||
|
if (MaybeInit()) {
|
||||||
|
RenderParams params(channel_id, window, zOrder, left, top, right, bottom);
|
||||||
|
return cricket::ChannelManager::Send(MSG_SETRTC_VIDEORENDERER, ¶ms);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WebRtcChannelManager::SetVideoRenderer_w(int channel_id,
|
||||||
|
void* window,
|
||||||
|
unsigned int zOrder,
|
||||||
|
float left,
|
||||||
|
float top,
|
||||||
|
float right,
|
||||||
|
float bottom) {
|
||||||
|
ASSERT(worker_thread() == talk_base::Thread::Current());
|
||||||
|
ASSERT(initialized());
|
||||||
|
media_engine()->SetVideoRenderer(channel_id, window, zOrder, left, top, right, bottom);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WebRtcChannelManager::OnMessage(talk_base::Message *message) {
|
||||||
|
talk_base::MessageData* data = message->pdata;
|
||||||
|
switch(message->message_id) {
|
||||||
|
case MSG_SETRTC_VIDEORENDERER: {
|
||||||
|
RenderParams* p = static_cast<RenderParams*>(data);
|
||||||
|
SetVideoRenderer_w(p->channel_id,
|
||||||
|
p->window,
|
||||||
|
p->zOrder,
|
||||||
|
p->left,
|
||||||
|
p->top,
|
||||||
|
p->right,
|
||||||
|
p->bottom);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
ChannelManager::OnMessage(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace webrtc
|
||||||
@ -0,0 +1,68 @@
|
|||||||
|
// Copyright 2011 Google Inc. All Rights Reserved.
|
||||||
|
// Author: mallinath@google.com (Mallinath Bareddy)
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef TALK_APP_WEBRTC_WEBRTCCHANNELMANAGER_H_
|
||||||
|
#define TALK_APP_WEBRTC_WEBRTCCHANNELMANAGER_H_
|
||||||
|
|
||||||
|
#include "talk/session/phone/channelmanager.h"
|
||||||
|
|
||||||
|
namespace webrtc {
|
||||||
|
|
||||||
|
class AudioDeviceModule;
|
||||||
|
|
||||||
|
enum {
|
||||||
|
MSG_SETRTC_VIDEORENDERER = 21, // Set internal video renderer
|
||||||
|
};
|
||||||
|
|
||||||
|
// WebRtcChannelManager automatically takes care of initialization and
|
||||||
|
// cricket::ChannelManager. Terminates when not needed
|
||||||
|
|
||||||
|
class WebRtcChannelManager : public cricket::ChannelManager {
|
||||||
|
public:
|
||||||
|
WebRtcChannelManager(talk_base::Thread* worker_thread)
|
||||||
|
: ChannelManager(worker_thread) {
|
||||||
|
}
|
||||||
|
|
||||||
|
WebRtcChannelManager(cricket::MediaEngine* me, cricket::DeviceManager* dm,
|
||||||
|
talk_base::Thread* worker_thread)
|
||||||
|
: ChannelManager(me, dm, worker_thread) {
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Init();
|
||||||
|
cricket::VoiceChannel* CreateVoiceChannel(
|
||||||
|
cricket::BaseSession* s, const std::string& content_name, bool rtcp);
|
||||||
|
cricket::VideoChannel* CreateVideoChannel(
|
||||||
|
cricket::BaseSession* s, const std::string& content_name, bool rtcp,
|
||||||
|
cricket::VoiceChannel* vc);
|
||||||
|
cricket::Soundclip* CreateSoundclip();
|
||||||
|
void DestroyVoiceChannel(cricket::VoiceChannel* vc);
|
||||||
|
void DestroyVideoChannel(cricket::VideoChannel* vc);
|
||||||
|
void DestroySoundclip(cricket::Soundclip* s);
|
||||||
|
|
||||||
|
bool SetVideoRenderer(int channel_id,
|
||||||
|
void* window,
|
||||||
|
unsigned int zOrder,
|
||||||
|
float left,
|
||||||
|
float top,
|
||||||
|
float right,
|
||||||
|
float bottom);
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool MaybeInit();
|
||||||
|
void MaybeTerm();
|
||||||
|
void SetExternalAdm_w(AudioDeviceModule* external_adm);
|
||||||
|
void SetVideoRenderer_w(int channel_id,
|
||||||
|
void* window,
|
||||||
|
unsigned int zOrder,
|
||||||
|
float left,
|
||||||
|
float top,
|
||||||
|
float right,
|
||||||
|
float bottom);
|
||||||
|
void OnMessage(talk_base::Message *message);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace webrtc
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* TALK_APP_WEBRTC_WEBRTCCHANNELMANAGER_H_ */
|
||||||
39
third_party_mods/libjingle/source/talk/app/webrtcsession.cc
Normal file
39
third_party_mods/libjingle/source/talk/app/webrtcsession.cc
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* libjingle
|
||||||
|
* Copyright 2004--2011, Google Inc.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
* 3. The name of the author may not be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||||
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||||
|
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||||
|
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||||
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||||
|
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||||
|
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "talk/app/webrtcsession.h"
|
||||||
|
|
||||||
|
namespace webrtc {
|
||||||
|
|
||||||
|
const std::string WebRTCSession::kOutgoingDirection = "s";
|
||||||
|
const std::string WebRTCSession::kIncomingDirection = "r";
|
||||||
|
//const std::string WebRTCSession::kAudioType = "a";
|
||||||
|
//const std::string WebRTCSession::kVideoType = "v";
|
||||||
|
//const std::string WebRTCSession::kTestType = "t";
|
||||||
|
|
||||||
|
} /* namespace webrtc */
|
||||||
|
|
||||||
100
third_party_mods/libjingle/source/talk/app/webrtcsession.h
Normal file
100
third_party_mods/libjingle/source/talk/app/webrtcsession.h
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
/*
|
||||||
|
* libjingle
|
||||||
|
* Copyright 2004--2011, Google Inc.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
* 3. The name of the author may not be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||||
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||||
|
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||||
|
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||||
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||||
|
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||||
|
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TALK_APP_WEBRTC_WEBRTCSESSION_H_
|
||||||
|
#define TALK_APP_WEBRTC_WEBRTCSESSION_H_
|
||||||
|
|
||||||
|
#include "talk/base/logging.h"
|
||||||
|
#include "talk/p2p/base/constants.h"
|
||||||
|
#include "talk/p2p/base/session.h"
|
||||||
|
|
||||||
|
namespace cricket {
|
||||||
|
class PortAllocator;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace webrtc {
|
||||||
|
class PeerConnection;
|
||||||
|
|
||||||
|
class WebRTCSession: public cricket::BaseSession {
|
||||||
|
public:
|
||||||
|
WebRTCSession(const std::string& id, const std::string& direction,
|
||||||
|
cricket::PortAllocator* allocator,
|
||||||
|
PeerConnection* connection,
|
||||||
|
talk_base::Thread* signaling_thread)
|
||||||
|
: BaseSession(signaling_thread),
|
||||||
|
signaling_thread_(signaling_thread),
|
||||||
|
id_(id),
|
||||||
|
incoming_(direction == kIncomingDirection),
|
||||||
|
port_allocator_(allocator),
|
||||||
|
connection_(connection) {
|
||||||
|
BaseSession::sid_ = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~WebRTCSession() {
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool Initiate() = 0;
|
||||||
|
|
||||||
|
const std::string& id() const { return id_; }
|
||||||
|
//const std::string& type() const { return type_; }
|
||||||
|
bool incoming() const { return incoming_; }
|
||||||
|
cricket::PortAllocator* port_allocator() const { return port_allocator_; }
|
||||||
|
|
||||||
|
// static const std::string kAudioType;
|
||||||
|
// static const std::string kVideoType;
|
||||||
|
static const std::string kIncomingDirection;
|
||||||
|
static const std::string kOutgoingDirection;
|
||||||
|
// static const std::string kTestType;
|
||||||
|
PeerConnection* connection() const { return connection_; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
//methods from cricket::BaseSession
|
||||||
|
virtual bool Accept(const cricket::SessionDescription* sdesc) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
virtual bool Reject(const std::string& reason) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
virtual bool TerminateWithReason(const std::string& reason) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
talk_base::Thread* signaling_thread_;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string id_;
|
||||||
|
//std::string type_;
|
||||||
|
bool incoming_;
|
||||||
|
cricket::PortAllocator* port_allocator_;
|
||||||
|
PeerConnection* connection_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace webrtc
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* TALK_APP_WEBRTC_WEBRTCSESSION_H_ */
|
||||||
1087
third_party_mods/libjingle/source/talk/app/webrtcsessionimpl.cc
Normal file
1087
third_party_mods/libjingle/source/talk/app/webrtcsessionimpl.cc
Normal file
File diff suppressed because it is too large
Load Diff
250
third_party_mods/libjingle/source/talk/app/webrtcsessionimpl.h
Normal file
250
third_party_mods/libjingle/source/talk/app/webrtcsessionimpl.h
Normal file
@ -0,0 +1,250 @@
|
|||||||
|
/*
|
||||||
|
* libjingle
|
||||||
|
* Copyright 2004--2011, Google Inc.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
* 3. The name of the author may not be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||||
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||||
|
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||||
|
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||||
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||||
|
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||||
|
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TALK_APP_WEBRTC_WEBRTCSESSIONIMPL_H_
|
||||||
|
#define TALK_APP_WEBRTC_WEBRTCSESSIONIMPL_H_
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "talk/base/messagehandler.h"
|
||||||
|
#include "talk/p2p/base/candidate.h"
|
||||||
|
#include "talk/session/phone/channel.h"
|
||||||
|
#include "talk/session/phone/mediachannel.h"
|
||||||
|
#include "talk/app/pc_transport_impl.h"
|
||||||
|
#include "talk/app/webrtcsession.h"
|
||||||
|
|
||||||
|
namespace cricket {
|
||||||
|
class ChannelManager;
|
||||||
|
class Transport;
|
||||||
|
class TransportChannel;
|
||||||
|
class VoiceChannel;
|
||||||
|
class VideoChannel;
|
||||||
|
struct ConnectionInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Json {
|
||||||
|
class Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace webrtc {
|
||||||
|
|
||||||
|
struct StreamInfo {
|
||||||
|
StreamInfo(const std::string stream_id)
|
||||||
|
: channel(NULL),
|
||||||
|
transport(NULL),
|
||||||
|
video(false),
|
||||||
|
stream_id(stream_id),
|
||||||
|
media_channel(-1) {}
|
||||||
|
|
||||||
|
StreamInfo()
|
||||||
|
: channel(NULL),
|
||||||
|
transport(NULL),
|
||||||
|
video(false),
|
||||||
|
media_channel(-1) {}
|
||||||
|
|
||||||
|
cricket::BaseChannel* channel;
|
||||||
|
PC_Transport_Impl* transport; //TODO - add RTCP transport channel
|
||||||
|
bool video;
|
||||||
|
std::string stream_id;
|
||||||
|
int media_channel;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::vector<cricket::AudioCodec> AudioCodecs;
|
||||||
|
typedef std::vector<cricket::VideoCodec> VideoCodecs;
|
||||||
|
|
||||||
|
class ExternalRenderer;
|
||||||
|
class PeerConnection;
|
||||||
|
class WebRtcChannelManager;
|
||||||
|
|
||||||
|
class WebRTCSessionImpl: public WebRTCSession {
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
WebRTCSessionImpl(const std::string& id,
|
||||||
|
const std::string& direction,
|
||||||
|
cricket::PortAllocator* allocator,
|
||||||
|
WebRtcChannelManager* channelmgr,
|
||||||
|
PeerConnection* connection,
|
||||||
|
talk_base::Thread* signaling_thread);
|
||||||
|
|
||||||
|
~WebRTCSessionImpl();
|
||||||
|
virtual bool Initiate();
|
||||||
|
virtual bool OnRemoteDescription(Json::Value& desc);
|
||||||
|
virtual bool OnRemoteDescription(const cricket::SessionDescription* sdp,
|
||||||
|
std::vector<cricket::Candidate>& candidates);
|
||||||
|
virtual bool OnInitiateMessage(const cricket::SessionDescription* sdp,
|
||||||
|
std::vector<cricket::Candidate>& candidates);
|
||||||
|
virtual void OnMute(bool mute);
|
||||||
|
virtual void OnCameraMute(bool mute);
|
||||||
|
|
||||||
|
// Override from BaseSession to allow setting errors from other threads
|
||||||
|
// than the signaling thread.
|
||||||
|
virtual void SetError(Error error);
|
||||||
|
|
||||||
|
bool muted() const { return muted_; }
|
||||||
|
bool camera_muted() const { return camera_muted_; }
|
||||||
|
|
||||||
|
bool CreateP2PTransportChannel(const std::string& stream_id, bool video);
|
||||||
|
|
||||||
|
bool CreateVoiceChannel(const std::string& stream_id);
|
||||||
|
bool CreateVideoChannel(const std::string& stream_id);
|
||||||
|
bool RemoveStream(const std::string& stream_id);
|
||||||
|
void RemoveAllStreams();
|
||||||
|
|
||||||
|
// Returns true if we have either a voice or video stream matching this label.
|
||||||
|
bool HasStream(const std::string& label) const;
|
||||||
|
bool HasStream(bool video) const;
|
||||||
|
|
||||||
|
// Returns true if there's one or more audio channels in the session.
|
||||||
|
bool HasAudioStream() const;
|
||||||
|
|
||||||
|
// Returns true if there's one or more video channels in the session.
|
||||||
|
bool HasVideoStream() const;
|
||||||
|
|
||||||
|
void OnCandidateReady(const cricket::Candidate& candidate);
|
||||||
|
void OnStateChange(P2PTransportClass::State state,
|
||||||
|
cricket::TransportChannel* channel);
|
||||||
|
void OnMessageReceived(const char* data, size_t data_size);
|
||||||
|
bool SetVideoRenderer(const std::string& stream_id,
|
||||||
|
ExternalRenderer* external_renderer);
|
||||||
|
bool SetVideoRenderer(int channel_id,
|
||||||
|
void* window,
|
||||||
|
unsigned int zOrder,
|
||||||
|
float left,
|
||||||
|
float top,
|
||||||
|
float right,
|
||||||
|
float bottom);
|
||||||
|
sigslot::signal2<cricket::VideoChannel*, std::string&> SignalVideoChannel;
|
||||||
|
sigslot::signal2<cricket::VoiceChannel*, std::string&> SignalVoiceChannel;
|
||||||
|
sigslot::signal1<WebRTCSessionImpl*> SignalOnRemoveStream;
|
||||||
|
|
||||||
|
void OnVoiceChannelCreated(cricket::VoiceChannel* voice_channel,
|
||||||
|
std::string& stream_id);
|
||||||
|
void OnVideoChannelCreated(cricket::VideoChannel* video_channel,
|
||||||
|
std::string& stream_id);
|
||||||
|
|
||||||
|
void ChannelEnable(cricket::BaseChannel* channel, bool enable);
|
||||||
|
|
||||||
|
std::vector<cricket::Candidate>& local_candidates() {
|
||||||
|
return local_candidates_;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool SetVideoRenderer_w(int channel_id,
|
||||||
|
void* window,
|
||||||
|
unsigned int zOrder,
|
||||||
|
float left,
|
||||||
|
float top,
|
||||||
|
float right,
|
||||||
|
float bottom);
|
||||||
|
void ChannelEnable_w(cricket::BaseChannel* channel, bool enable);
|
||||||
|
|
||||||
|
void OnVoiceChannelError(cricket::VoiceChannel* voice_channel, uint32 ssrc,
|
||||||
|
cricket::VoiceMediaChannel::Error error);
|
||||||
|
void OnVideoChannelError(cricket::VideoChannel* video_channel, uint32 ssrc,
|
||||||
|
cricket::VideoMediaChannel::Error error);
|
||||||
|
|
||||||
|
// methods signaled by the transport
|
||||||
|
void OnRequestSignaling(cricket::Transport* transport);
|
||||||
|
void OnCandidatesReady(cricket::Transport* transport,
|
||||||
|
const std::vector<cricket::Candidate>& candidates);
|
||||||
|
void OnWritableState(cricket::Transport* transport);
|
||||||
|
|
||||||
|
// transport-management overrides from cricket::BaseSession
|
||||||
|
virtual cricket::TransportChannel* CreateChannel(
|
||||||
|
const std::string& content_name, const std::string& name);
|
||||||
|
virtual cricket::TransportChannel* GetChannel(
|
||||||
|
const std::string& content_name, const std::string& name);
|
||||||
|
virtual void DestroyChannel(
|
||||||
|
const std::string& content_name, const std::string& name);
|
||||||
|
|
||||||
|
virtual talk_base::Thread* worker_thread() {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
void SendLocalDescription();
|
||||||
|
|
||||||
|
void UpdateTransportWritableState();
|
||||||
|
bool CheckAllTransportsWritable();
|
||||||
|
void StartTransportTimeout(int timeout);
|
||||||
|
void ClearTransportTimeout();
|
||||||
|
void NotifyTransportState();
|
||||||
|
|
||||||
|
cricket::SessionDescription* CreateOffer();
|
||||||
|
cricket::SessionDescription* CreateAnswer(
|
||||||
|
const cricket::SessionDescription* answer);
|
||||||
|
|
||||||
|
//from MessageHandler
|
||||||
|
virtual void OnMessage(talk_base::Message* message);
|
||||||
|
|
||||||
|
private:
|
||||||
|
typedef std::map<std::string, PC_Transport_Impl*> TransportChannelMap;
|
||||||
|
|
||||||
|
cricket::VideoChannel* CreateVideoChannel_w(
|
||||||
|
const std::string& content_name,
|
||||||
|
bool rtcp,
|
||||||
|
cricket::VoiceChannel* voice_channel);
|
||||||
|
|
||||||
|
cricket::VoiceChannel* CreateVoiceChannel_w(
|
||||||
|
const std::string& content_name,
|
||||||
|
bool rtcp);
|
||||||
|
|
||||||
|
void DestroyVoiceChannel_w(cricket::VoiceChannel* channel);
|
||||||
|
void DestroyVideoChannel_w(cricket::VideoChannel* channel);
|
||||||
|
void SignalOnWritableState_w(cricket::TransportChannel* channel);
|
||||||
|
|
||||||
|
void SetSessionState(State state);
|
||||||
|
void SetSessionState_w();
|
||||||
|
bool SetVideoCapture(bool capture);
|
||||||
|
cricket::CaptureResult SetVideoCapture_w(bool capture);
|
||||||
|
void DisableLocalCandidate(const std::string& name);
|
||||||
|
bool OnRemoteDescriptionUpdate(const cricket::SessionDescription* desc,
|
||||||
|
std::vector<cricket::Candidate>& candidates);
|
||||||
|
void RemoveStreamOnRequest(const cricket::Candidate& candidate);
|
||||||
|
void RemoveStream_w(const std::string& stream_id);
|
||||||
|
void RemoveAllStreams_w();
|
||||||
|
|
||||||
|
void EnableAllStreams_w();
|
||||||
|
|
||||||
|
void SendLocalDescription_w();
|
||||||
|
|
||||||
|
WebRtcChannelManager* channel_manager_;
|
||||||
|
std::vector<StreamInfo*> streams_;
|
||||||
|
TransportChannelMap transport_channels_;
|
||||||
|
bool all_writable_;
|
||||||
|
bool muted_;
|
||||||
|
bool camera_muted_;
|
||||||
|
int setup_timeout_;
|
||||||
|
std::vector<cricket::Candidate> local_candidates_;
|
||||||
|
std::vector<cricket::Candidate> remote_candidates_;
|
||||||
|
State session_state_;
|
||||||
|
bool signal_initiated_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} /* namespace webrtc */
|
||||||
|
|
||||||
|
#endif /* TALK_APP_WEBRTC_WEBRTCSESSIONIMPL_H_ */
|
||||||
@ -0,0 +1,100 @@
|
|||||||
|
/*
|
||||||
|
* webrtcsessionimpl_unittest.cc
|
||||||
|
*
|
||||||
|
* Created on: Mar 11, 2011
|
||||||
|
* Author: mallinath
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "talk/base/gunit.h"
|
||||||
|
#include "talk/base/logging.h"
|
||||||
|
#include "talk/base/scoped_ptr.h"
|
||||||
|
#include "talk/base/sigslot.h"
|
||||||
|
#include "talk/app/webrtcsessionimpl.h"
|
||||||
|
#include "talk/p2p/client/basicportallocator.h"
|
||||||
|
#include "talk/session/phone/channelmanager.h"
|
||||||
|
#include "talk/session/phone/fakemediaengine.h"
|
||||||
|
#include "talk/session/phone/fakesession.h"
|
||||||
|
|
||||||
|
namespace webrtc {
|
||||||
|
using talk_base::scoped_ptr;
|
||||||
|
|
||||||
|
static const char* kTestSessionId = "1234";
|
||||||
|
|
||||||
|
class WebRTCSessionImplForTest : public WebRTCSessionImpl {
|
||||||
|
public:
|
||||||
|
WebRTCSessionImplForTest(const std::string& jid, const std::string& id,
|
||||||
|
const std::string& type,
|
||||||
|
const std::string& direction,
|
||||||
|
cricket::PortAllocator* allocator,
|
||||||
|
cricket::ChannelManager* channelmgr)
|
||||||
|
: WebRTCSessionImpl(NULL, id, type, direction, allocator, channelmgr) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
~WebRTCSessionImplForTest() {
|
||||||
|
//Do Nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual cricket::Transport* GetTransport() {
|
||||||
|
return static_cast<cricket::FakeTransport*>(WebRTCSessionImpl::GetTransport());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual cricket::Transport* CreateTransport() {
|
||||||
|
return new cricket::FakeTransport(talk_base::Thread::Current(), talk_base::Thread::Current());
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class WebRTCSessionImplTest : public sigslot::has_slots<>,
|
||||||
|
public testing::Test {
|
||||||
|
public:
|
||||||
|
WebRTCSessionImplTest() {
|
||||||
|
network_mgr_.reset(new talk_base::NetworkManager());
|
||||||
|
port_allocator_.reset(new cricket::BasicPortAllocator(network_mgr_.get()));
|
||||||
|
media_engine_ = new cricket::FakeMediaEngine();
|
||||||
|
channel_mgr_.reset(new cricket::ChannelManager(talk_base::Thread::Current()));
|
||||||
|
channel_mgr_.reset(NULL);
|
||||||
|
|
||||||
|
}
|
||||||
|
~WebRTCSessionImplTest() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void CreateSession(const std::string& jid, const std::string& id,
|
||||||
|
const std::string& type, const std::string& dir) {
|
||||||
|
session_.reset(new WebRTCSessionImplForTest(jid, id, type, dir,
|
||||||
|
port_allocator_.get(),
|
||||||
|
channel_mgr_.get()));
|
||||||
|
}
|
||||||
|
bool InitiateCall(const std::string& jid, const std::string& id,
|
||||||
|
const std::string& type, const std::string& dir) {
|
||||||
|
CreateSession(jid, id, type, dir);
|
||||||
|
bool ret = session_->Initiate();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GetCandidates() {
|
||||||
|
return InitiateCall("", kTestSessionId, "t", "s");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected:
|
||||||
|
scoped_ptr<talk_base::NetworkManager> network_mgr_;
|
||||||
|
scoped_ptr<cricket::BasicPortAllocator> port_allocator_;
|
||||||
|
cricket::FakeMediaEngine* media_engine_;
|
||||||
|
scoped_ptr<cricket::ChannelManager> channel_mgr_;
|
||||||
|
scoped_ptr<WebRTCSessionImplForTest> session_;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_F(WebRTCSessionImplTest, TestGetCandidatesCall) {
|
||||||
|
EXPECT_TRUE(GetCandidates());
|
||||||
|
EXPECT_EQ(cricket::Session::STATE_INIT, session_->state());
|
||||||
|
EXPECT_EQ(kTestSessionId, session_->id());
|
||||||
|
EXPECT_EQ(WebRTCSession::kTestType, session_->type());
|
||||||
|
EXPECT_FALSE(session_->incoming());
|
||||||
|
}
|
||||||
|
|
||||||
|
} /* namespace webrtc */
|
||||||
217
third_party_mods/libjingle/source/talk/base/json.cc
Normal file
217
third_party_mods/libjingle/source/talk/base/json.cc
Normal file
@ -0,0 +1,217 @@
|
|||||||
|
/*
|
||||||
|
* 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/base/json.h"
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include <climits>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
bool GetStringFromJson(const Json::Value& in, std::string* out) {
|
||||||
|
if (!in.isString()) {
|
||||||
|
std::ostringstream s;
|
||||||
|
if (in.isBool()) {
|
||||||
|
s << std::boolalpha << in.asBool();
|
||||||
|
} else if (in.isInt()) {
|
||||||
|
s << in.asInt();
|
||||||
|
} else if (in.isUInt()) {
|
||||||
|
s << in.asUInt();
|
||||||
|
} else if (in.isDouble()) {
|
||||||
|
s << in.asDouble();
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
*out = s.str();
|
||||||
|
} else {
|
||||||
|
*out = in.asString();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GetIntFromJson(const Json::Value& in, int* out) {
|
||||||
|
bool ret;
|
||||||
|
if (!in.isString()) {
|
||||||
|
ret = in.isConvertibleTo(Json::intValue);
|
||||||
|
if (ret) {
|
||||||
|
*out = in.asInt();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
long val; // NOLINT
|
||||||
|
const char* c_str = in.asCString();
|
||||||
|
char* end_ptr;
|
||||||
|
errno = 0;
|
||||||
|
val = strtol(c_str, &end_ptr, 10); // NOLINT
|
||||||
|
ret = (end_ptr != c_str && *end_ptr == '\0' && !errno &&
|
||||||
|
val >= INT_MIN && val <= INT_MAX);
|
||||||
|
*out = val;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GetUIntFromJson(const Json::Value& in, unsigned int* out) {
|
||||||
|
bool ret;
|
||||||
|
if (!in.isString()) {
|
||||||
|
ret = in.isConvertibleTo(Json::uintValue);
|
||||||
|
if (ret) {
|
||||||
|
*out = in.asUInt();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
unsigned long val; // NOLINT
|
||||||
|
const char* c_str = in.asCString();
|
||||||
|
char* end_ptr;
|
||||||
|
errno = 0;
|
||||||
|
val = strtoul(c_str, &end_ptr, 10); // NOLINT
|
||||||
|
ret = (end_ptr != c_str && *end_ptr == '\0' && !errno &&
|
||||||
|
val <= UINT_MAX);
|
||||||
|
*out = val;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GetBoolFromJson(const Json::Value& in, bool* out) {
|
||||||
|
bool ret;
|
||||||
|
if (!in.isString()) {
|
||||||
|
ret = in.isConvertibleTo(Json::booleanValue);
|
||||||
|
if (ret) {
|
||||||
|
*out = in.asBool();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (in.asString() == "true") {
|
||||||
|
*out = true;
|
||||||
|
ret = true;
|
||||||
|
} else if (in.asString() == "false") {
|
||||||
|
*out = false;
|
||||||
|
ret = true;
|
||||||
|
} else {
|
||||||
|
ret = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GetValueFromJsonArray(const Json::Value& in, size_t n,
|
||||||
|
Json::Value* out) {
|
||||||
|
if (!in.isArray() || !in.isValidIndex(n)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
*out = in[n];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GetIntFromJsonArray(const Json::Value& in, size_t n,
|
||||||
|
int* out) {
|
||||||
|
Json::Value x;
|
||||||
|
return GetValueFromJsonArray(in, n, &x) && GetIntFromJson(x, out);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GetUIntFromJsonArray(const Json::Value& in, size_t n,
|
||||||
|
unsigned int* out) {
|
||||||
|
Json::Value x;
|
||||||
|
return GetValueFromJsonArray(in, n, &x) && GetUIntFromJson(x, out);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GetStringFromJsonArray(const Json::Value& in, size_t n,
|
||||||
|
std::string* out) {
|
||||||
|
Json::Value x;
|
||||||
|
return GetValueFromJsonArray(in, n, &x) && GetStringFromJson(x, out);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GetBoolFromJsonArray(const Json::Value& in, size_t n,
|
||||||
|
bool* out) {
|
||||||
|
Json::Value x;
|
||||||
|
return GetValueFromJsonArray(in, n, &x) && GetBoolFromJson(x, out);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GetValueFromJsonObject(const Json::Value& in, const std::string& k,
|
||||||
|
Json::Value* out) {
|
||||||
|
if (!in.isObject() || !in.isMember(k)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
*out = in[k];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool GetIntFromJsonObject(const Json::Value& in, const std::string& k,
|
||||||
|
int* out) {
|
||||||
|
Json::Value x;
|
||||||
|
return GetValueFromJsonObject(in, k, &x) && GetIntFromJson(x, out);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GetUIntFromJsonObject(const Json::Value& in, const std::string& k,
|
||||||
|
unsigned int* out) {
|
||||||
|
Json::Value x;
|
||||||
|
return GetValueFromJsonObject(in, k, &x) && GetUIntFromJson(x, out);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GetStringFromJsonObject(const Json::Value& in, const std::string& k,
|
||||||
|
std::string* out) {
|
||||||
|
Json::Value x;
|
||||||
|
return GetValueFromJsonObject(in, k, &x) && GetStringFromJson(x, out);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GetBoolFromJsonObject(const Json::Value& in, const std::string& k,
|
||||||
|
bool* out) {
|
||||||
|
Json::Value x;
|
||||||
|
return GetValueFromJsonObject(in, k, &x) && GetBoolFromJson(x, out);
|
||||||
|
}
|
||||||
|
|
||||||
|
Json::Value StringVectorToJsonValue(const std::vector<std::string>& strings) {
|
||||||
|
Json::Value result(Json::arrayValue);
|
||||||
|
for (size_t i = 0; i < strings.size(); ++i) {
|
||||||
|
result.append(Json::Value(strings[i]));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool JsonValueToStringVector(const Json::Value& value,
|
||||||
|
std::vector<std::string> *strings) {
|
||||||
|
strings->clear();
|
||||||
|
if (!value.isArray()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < value.size(); ++i) {
|
||||||
|
if (value[i].isString()) {
|
||||||
|
strings->push_back(value[i].asString());
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string JsonValueToString(const Json::Value& json) {
|
||||||
|
Json::FastWriter w;
|
||||||
|
std::string value = w.write(json);
|
||||||
|
return value.substr(0, value.size() - 1); // trim trailing newline
|
||||||
|
}
|
||||||
80
third_party_mods/libjingle/source/talk/base/json.h
Normal file
80
third_party_mods/libjingle/source/talk/base/json.h
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
/*
|
||||||
|
* 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 TALK_BASE_JSON_H_
|
||||||
|
#define TALK_BASE_JSON_H_
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "json/json.h"
|
||||||
|
|
||||||
|
// TODO(juberti): Move to talk_base namespace
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// JSON Helpers
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// Robust conversion operators, better than the ones in JsonCpp.
|
||||||
|
bool GetIntFromJson(const Json::Value& in, int* out);
|
||||||
|
bool GetUIntFromJson(const Json::Value& in, unsigned int* out);
|
||||||
|
bool GetStringFromJson(const Json::Value& in, std::string* out);
|
||||||
|
bool GetBoolFromJson(const Json::Value& in, bool* out);
|
||||||
|
|
||||||
|
// Pull values out of a JSON array.
|
||||||
|
bool GetValueFromJsonArray(const Json::Value& in, size_t n,
|
||||||
|
Json::Value* out);
|
||||||
|
bool GetIntFromJsonArray(const Json::Value& in, size_t n,
|
||||||
|
int* out);
|
||||||
|
bool GetUIntFromJsonArray(const Json::Value& in, size_t n,
|
||||||
|
unsigned int* out);
|
||||||
|
bool GetStringFromJsonArray(const Json::Value& in, size_t n,
|
||||||
|
std::string* out);
|
||||||
|
bool GetBoolFromJsonArray(const Json::Value& in, size_t n,
|
||||||
|
bool* out);
|
||||||
|
|
||||||
|
// Pull values out of a JSON object.
|
||||||
|
bool GetValueFromJsonObject(const Json::Value& in, const std::string& k,
|
||||||
|
Json::Value* out);
|
||||||
|
bool GetIntFromJsonObject(const Json::Value& in, const std::string& k,
|
||||||
|
int* out);
|
||||||
|
bool GetUIntFromJsonObject(const Json::Value& in, const std::string& k,
|
||||||
|
unsigned int* out);
|
||||||
|
bool GetStringFromJsonObject(const Json::Value& in, const std::string& k,
|
||||||
|
std::string* out);
|
||||||
|
bool GetBoolFromJsonObject(const Json::Value& in, const std::string& k,
|
||||||
|
bool* out);
|
||||||
|
|
||||||
|
// Converts vectors of strings to/from JSON arrays.
|
||||||
|
Json::Value StringVectorToJsonValue(const std::vector<std::string>& strings);
|
||||||
|
bool JsonValueToStringVector(const Json::Value& value,
|
||||||
|
std::vector<std::string> *strings);
|
||||||
|
|
||||||
|
// Writes out a Json value as a string.
|
||||||
|
std::string JsonValueToString(const Json::Value& json);
|
||||||
|
|
||||||
|
#endif // TALK_BASE_JSON_H_
|
||||||
@ -0,0 +1,972 @@
|
|||||||
|
/*
|
||||||
|
* 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/p2p/base/p2ptransportchannel.h"
|
||||||
|
|
||||||
|
#include <set>
|
||||||
|
|
||||||
|
#include "talk/base/buffer.h"
|
||||||
|
#include "talk/base/common.h"
|
||||||
|
#include "talk/base/logging.h"
|
||||||
|
#include "talk/p2p/base/common.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
// messages for queuing up work for ourselves
|
||||||
|
const uint32 MSG_SORT = 1;
|
||||||
|
const uint32 MSG_PING = 2;
|
||||||
|
const uint32 MSG_ALLOCATE = 3;
|
||||||
|
|
||||||
|
#ifdef PLATFORM_CHROMIUM
|
||||||
|
const uint32 MSG_SENDPACKET = 4;
|
||||||
|
|
||||||
|
struct SendPacketParams : public talk_base::MessageData {
|
||||||
|
talk_base::Buffer packet;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// When the socket is unwritable, we will use 10 Kbps (ignoring IP+UDP headers)
|
||||||
|
// for pinging. When the socket is writable, we will use only 1 Kbps because
|
||||||
|
// we don't want to degrade the quality on a modem. These numbers should work
|
||||||
|
// well on a 28.8K modem, which is the slowest connection on which the voice
|
||||||
|
// quality is reasonable at all.
|
||||||
|
static const uint32 PING_PACKET_SIZE = 60 * 8;
|
||||||
|
static const uint32 WRITABLE_DELAY = 1000 * PING_PACKET_SIZE / 1000; // 480ms
|
||||||
|
static const uint32 UNWRITABLE_DELAY = 1000 * PING_PACKET_SIZE / 10000; // 50ms
|
||||||
|
|
||||||
|
// If there is a current writable connection, then we will also try hard to
|
||||||
|
// make sure it is pinged at this rate.
|
||||||
|
static const uint32 MAX_CURRENT_WRITABLE_DELAY = 900; // 2*WRITABLE_DELAY - bit
|
||||||
|
|
||||||
|
// The minimum improvement in RTT that justifies a switch.
|
||||||
|
static const double kMinImprovement = 10;
|
||||||
|
|
||||||
|
// Amount of time that we wait when *losing* writability before we try doing
|
||||||
|
// another allocation.
|
||||||
|
static const int kAllocateDelay = 1 * 1000; // 1 second
|
||||||
|
|
||||||
|
// We will try creating a new allocator from scratch after a delay of this
|
||||||
|
// length without becoming writable (or timing out).
|
||||||
|
static const int kAllocatePeriod = 20 * 1000; // 20 seconds
|
||||||
|
|
||||||
|
cricket::Port::CandidateOrigin GetOrigin(cricket::Port* port,
|
||||||
|
cricket::Port* origin_port) {
|
||||||
|
if (!origin_port)
|
||||||
|
return cricket::Port::ORIGIN_MESSAGE;
|
||||||
|
else if (port == origin_port)
|
||||||
|
return cricket::Port::ORIGIN_THIS_PORT;
|
||||||
|
else
|
||||||
|
return cricket::Port::ORIGIN_OTHER_PORT;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compares two connections based only on static information about them.
|
||||||
|
int CompareConnectionCandidates(cricket::Connection* a,
|
||||||
|
cricket::Connection* b) {
|
||||||
|
// Combine local and remote preferences
|
||||||
|
ASSERT(a->local_candidate().preference() == a->port()->preference());
|
||||||
|
ASSERT(b->local_candidate().preference() == b->port()->preference());
|
||||||
|
double a_pref = a->local_candidate().preference()
|
||||||
|
* a->remote_candidate().preference();
|
||||||
|
double b_pref = b->local_candidate().preference()
|
||||||
|
* b->remote_candidate().preference();
|
||||||
|
|
||||||
|
// Now check combined preferences. Lower values get sorted last.
|
||||||
|
if (a_pref > b_pref)
|
||||||
|
return 1;
|
||||||
|
if (a_pref < b_pref)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
// If we're still tied at this point, prefer a younger generation.
|
||||||
|
return (a->remote_candidate().generation() + a->port()->generation()) -
|
||||||
|
(b->remote_candidate().generation() + b->port()->generation());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compare two connections based on their writability and static preferences.
|
||||||
|
int CompareConnections(cricket::Connection *a, cricket::Connection *b) {
|
||||||
|
// Sort based on write-state. Better states have lower values.
|
||||||
|
if (a->write_state() < b->write_state())
|
||||||
|
return 1;
|
||||||
|
if (a->write_state() > b->write_state())
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
// Compare the candidate information.
|
||||||
|
return CompareConnectionCandidates(a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wraps the comparison connection into a less than operator that puts higher
|
||||||
|
// priority writable connections first.
|
||||||
|
class ConnectionCompare {
|
||||||
|
public:
|
||||||
|
bool operator()(const cricket::Connection *ca,
|
||||||
|
const cricket::Connection *cb) {
|
||||||
|
cricket::Connection* a = const_cast<cricket::Connection*>(ca);
|
||||||
|
cricket::Connection* b = const_cast<cricket::Connection*>(cb);
|
||||||
|
|
||||||
|
// Compare first on writability and static preferences.
|
||||||
|
int cmp = CompareConnections(a, b);
|
||||||
|
if (cmp > 0)
|
||||||
|
return true;
|
||||||
|
if (cmp < 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Otherwise, sort based on latency estimate.
|
||||||
|
return a->rtt() < b->rtt();
|
||||||
|
|
||||||
|
// Should we bother checking for the last connection that last received
|
||||||
|
// data? It would help rendezvous on the connection that is also receiving
|
||||||
|
// packets.
|
||||||
|
//
|
||||||
|
// TODO: Yes we should definitely do this. The TCP protocol gains
|
||||||
|
// efficiency by being used bidirectionally, as opposed to two separate
|
||||||
|
// unidirectional streams. This test should probably occur before
|
||||||
|
// comparison of local prefs (assuming combined prefs are the same). We
|
||||||
|
// need to be careful though, not to bounce back and forth with both sides
|
||||||
|
// trying to rendevous with the other.
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Determines whether we should switch between two connections, based first on
|
||||||
|
// static preferences and then (if those are equal) on latency estimates.
|
||||||
|
bool ShouldSwitch(cricket::Connection* a_conn, cricket::Connection* b_conn) {
|
||||||
|
if (a_conn == b_conn)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!a_conn || !b_conn) // don't think the latter should happen
|
||||||
|
return true;
|
||||||
|
|
||||||
|
int prefs_cmp = CompareConnections(a_conn, b_conn);
|
||||||
|
if (prefs_cmp < 0)
|
||||||
|
return true;
|
||||||
|
if (prefs_cmp > 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return b_conn->rtt() <= a_conn->rtt() + kMinImprovement;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // unnamed namespace
|
||||||
|
|
||||||
|
namespace cricket {
|
||||||
|
|
||||||
|
P2PTransportChannel::P2PTransportChannel(const std::string &name,
|
||||||
|
const std::string &content_type,
|
||||||
|
P2PTransport* transport,
|
||||||
|
PortAllocator *allocator) :
|
||||||
|
TransportChannelImpl(name, content_type),
|
||||||
|
transport_(transport),
|
||||||
|
allocator_(allocator),
|
||||||
|
worker_thread_(talk_base::Thread::Current()),
|
||||||
|
incoming_only_(false),
|
||||||
|
waiting_for_signaling_(false),
|
||||||
|
error_(0),
|
||||||
|
best_connection_(NULL),
|
||||||
|
pinging_started_(false),
|
||||||
|
sort_dirty_(false),
|
||||||
|
was_writable_(false),
|
||||||
|
was_timed_out_(true) {
|
||||||
|
}
|
||||||
|
|
||||||
|
P2PTransportChannel::~P2PTransportChannel() {
|
||||||
|
ASSERT(worker_thread_ == talk_base::Thread::Current());
|
||||||
|
|
||||||
|
for (uint32 i = 0; i < allocator_sessions_.size(); ++i)
|
||||||
|
delete allocator_sessions_[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the allocator session to our list so that we know which sessions
|
||||||
|
// are still active.
|
||||||
|
void P2PTransportChannel::AddAllocatorSession(PortAllocatorSession* session) {
|
||||||
|
session->set_generation(static_cast<uint32>(allocator_sessions_.size()));
|
||||||
|
allocator_sessions_.push_back(session);
|
||||||
|
|
||||||
|
// We now only want to apply new candidates that we receive to the ports
|
||||||
|
// created by this new session because these are replacing those of the
|
||||||
|
// previous sessions.
|
||||||
|
ports_.clear();
|
||||||
|
|
||||||
|
session->SignalPortReady.connect(this, &P2PTransportChannel::OnPortReady);
|
||||||
|
session->SignalCandidatesReady.connect(
|
||||||
|
this, &P2PTransportChannel::OnCandidatesReady);
|
||||||
|
session->GetInitialPorts();
|
||||||
|
if (pinging_started_)
|
||||||
|
session->StartGetAllPorts();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Go into the state of processing candidates, and running in general
|
||||||
|
void P2PTransportChannel::Connect() {
|
||||||
|
ASSERT(worker_thread_ == talk_base::Thread::Current());
|
||||||
|
|
||||||
|
// Kick off an allocator session
|
||||||
|
Allocate();
|
||||||
|
|
||||||
|
// Start pinging as the ports come in.
|
||||||
|
thread()->Post(this, MSG_PING);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset the socket, clear up any previous allocations and start over
|
||||||
|
void P2PTransportChannel::Reset() {
|
||||||
|
ASSERT(worker_thread_ == talk_base::Thread::Current());
|
||||||
|
|
||||||
|
// Get rid of all the old allocators. This should clean up everything.
|
||||||
|
for (uint32 i = 0; i < allocator_sessions_.size(); ++i)
|
||||||
|
delete allocator_sessions_[i];
|
||||||
|
|
||||||
|
allocator_sessions_.clear();
|
||||||
|
ports_.clear();
|
||||||
|
connections_.clear();
|
||||||
|
best_connection_ = NULL;
|
||||||
|
|
||||||
|
// Forget about all of the candidates we got before.
|
||||||
|
remote_candidates_.clear();
|
||||||
|
|
||||||
|
// Revert to the initial state.
|
||||||
|
set_readable(false);
|
||||||
|
set_writable(false);
|
||||||
|
|
||||||
|
// Reinitialize the rest of our state.
|
||||||
|
waiting_for_signaling_ = false;
|
||||||
|
pinging_started_ = false;
|
||||||
|
sort_dirty_ = false;
|
||||||
|
was_writable_ = false;
|
||||||
|
was_timed_out_ = true;
|
||||||
|
|
||||||
|
// If we allocated before, start a new one now.
|
||||||
|
if (transport_->connect_requested())
|
||||||
|
Allocate();
|
||||||
|
|
||||||
|
// Start pinging as the ports come in.
|
||||||
|
thread()->Clear(this);
|
||||||
|
thread()->Post(this, MSG_PING);
|
||||||
|
}
|
||||||
|
|
||||||
|
// A new port is available, attempt to make connections for it
|
||||||
|
void P2PTransportChannel::OnPortReady(PortAllocatorSession *session,
|
||||||
|
Port* port) {
|
||||||
|
ASSERT(worker_thread_ == talk_base::Thread::Current());
|
||||||
|
|
||||||
|
// Set in-effect options on the new port
|
||||||
|
for (OptionMap::const_iterator it = options_.begin();
|
||||||
|
it != options_.end();
|
||||||
|
++it) {
|
||||||
|
int val = port->SetOption(it->first, it->second);
|
||||||
|
if (val < 0) {
|
||||||
|
LOG_J(LS_WARNING, port) << "SetOption(" << it->first
|
||||||
|
<< ", " << it->second
|
||||||
|
<< ") failed: " << port->GetError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remember the ports and candidates, and signal that candidates are ready.
|
||||||
|
// The session will handle this, and send an initiate/accept/modify message
|
||||||
|
// if one is pending.
|
||||||
|
|
||||||
|
ports_.push_back(port);
|
||||||
|
port->SignalUnknownAddress.connect(
|
||||||
|
this, &P2PTransportChannel::OnUnknownAddress);
|
||||||
|
port->SignalDestroyed.connect(this, &P2PTransportChannel::OnPortDestroyed);
|
||||||
|
|
||||||
|
// Attempt to create a connection from this new port to all of the remote
|
||||||
|
// candidates that we were given so far.
|
||||||
|
|
||||||
|
std::vector<RemoteCandidate>::iterator iter;
|
||||||
|
for (iter = remote_candidates_.begin(); iter != remote_candidates_.end();
|
||||||
|
++iter) {
|
||||||
|
CreateConnection(port, *iter, iter->origin_port(), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
SortConnections();
|
||||||
|
}
|
||||||
|
|
||||||
|
// A new candidate is available, let listeners know
|
||||||
|
void P2PTransportChannel::OnCandidatesReady(
|
||||||
|
PortAllocatorSession *session, const std::vector<Candidate>& candidates) {
|
||||||
|
for (size_t i = 0; i < candidates.size(); ++i) {
|
||||||
|
SignalCandidateReady(this, candidates[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle stun packets
|
||||||
|
void P2PTransportChannel::OnUnknownAddress(
|
||||||
|
Port *port, const talk_base::SocketAddress &address, StunMessage *stun_msg,
|
||||||
|
const std::string &remote_username) {
|
||||||
|
ASSERT(worker_thread_ == talk_base::Thread::Current());
|
||||||
|
|
||||||
|
// Port has received a valid stun packet from an address that no Connection
|
||||||
|
// is currently available for. See if the remote user name is in the remote
|
||||||
|
// candidate list. If it isn't return error to the stun request.
|
||||||
|
|
||||||
|
const Candidate *candidate = NULL;
|
||||||
|
std::vector<RemoteCandidate>::iterator it;
|
||||||
|
for (it = remote_candidates_.begin(); it != remote_candidates_.end(); ++it) {
|
||||||
|
if ((*it).username() == remote_username) {
|
||||||
|
candidate = &(*it);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (candidate == NULL) {
|
||||||
|
// Don't know about this username, the request is bogus
|
||||||
|
// This sometimes happens if a binding response comes in before the ACCEPT
|
||||||
|
// message. It is totally valid; the retry state machine will try again.
|
||||||
|
|
||||||
|
port->SendBindingErrorResponse(stun_msg, address,
|
||||||
|
STUN_ERROR_STALE_CREDENTIALS, STUN_ERROR_REASON_STALE_CREDENTIALS);
|
||||||
|
delete stun_msg;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for connectivity to this address. Create connections
|
||||||
|
// to this address across all local ports. First, add this as a new remote
|
||||||
|
// address
|
||||||
|
|
||||||
|
Candidate new_remote_candidate = *candidate;
|
||||||
|
new_remote_candidate.set_address(address);
|
||||||
|
// new_remote_candidate.set_protocol(port->protocol());
|
||||||
|
|
||||||
|
// This remote username exists. Now create connections using this candidate,
|
||||||
|
// and resort
|
||||||
|
|
||||||
|
if (CreateConnections(new_remote_candidate, port, true)) {
|
||||||
|
// Send the pinger a successful stun response.
|
||||||
|
port->SendBindingResponse(stun_msg, address);
|
||||||
|
|
||||||
|
// Update the list of connections since we just added another. We do this
|
||||||
|
// after sending the response since it could (in principle) delete the
|
||||||
|
// connection in question.
|
||||||
|
SortConnections();
|
||||||
|
} else {
|
||||||
|
// Hopefully this won't occur, because changing a destination address
|
||||||
|
// shouldn't cause a new connection to fail
|
||||||
|
ASSERT(false);
|
||||||
|
port->SendBindingErrorResponse(stun_msg, address, STUN_ERROR_SERVER_ERROR,
|
||||||
|
STUN_ERROR_REASON_SERVER_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
delete stun_msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
void P2PTransportChannel::OnCandidate(const Candidate& candidate) {
|
||||||
|
ASSERT(worker_thread_ == talk_base::Thread::Current());
|
||||||
|
|
||||||
|
// Create connections to this remote candidate.
|
||||||
|
CreateConnections(candidate, NULL, false);
|
||||||
|
|
||||||
|
// Resort the connections list, which may have new elements.
|
||||||
|
SortConnections();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates connections from all of the ports that we care about to the given
|
||||||
|
// remote candidate. The return value is true if we created a connection from
|
||||||
|
// the origin port.
|
||||||
|
bool P2PTransportChannel::CreateConnections(const Candidate &remote_candidate,
|
||||||
|
Port* origin_port,
|
||||||
|
bool readable) {
|
||||||
|
ASSERT(worker_thread_ == talk_base::Thread::Current());
|
||||||
|
|
||||||
|
// Add a new connection for this candidate to every port that allows such a
|
||||||
|
// connection (i.e., if they have compatible protocols) and that does not
|
||||||
|
// already have a connection to an equivalent candidate. We must be careful
|
||||||
|
// to make sure that the origin port is included, even if it was pruned,
|
||||||
|
// since that may be the only port that can create this connection.
|
||||||
|
|
||||||
|
bool created = false;
|
||||||
|
|
||||||
|
std::vector<Port *>::reverse_iterator it;
|
||||||
|
for (it = ports_.rbegin(); it != ports_.rend(); ++it) {
|
||||||
|
if (CreateConnection(*it, remote_candidate, origin_port, readable)) {
|
||||||
|
if (*it == origin_port)
|
||||||
|
created = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((origin_port != NULL) &&
|
||||||
|
std::find(ports_.begin(), ports_.end(), origin_port) == ports_.end()) {
|
||||||
|
if (CreateConnection(origin_port, remote_candidate, origin_port, readable))
|
||||||
|
created = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remember this remote candidate so that we can add it to future ports.
|
||||||
|
RememberRemoteCandidate(remote_candidate, origin_port);
|
||||||
|
|
||||||
|
return created;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup a connection object for the local and remote candidate combination.
|
||||||
|
// And then listen to connection object for changes.
|
||||||
|
bool P2PTransportChannel::CreateConnection(Port* port,
|
||||||
|
const Candidate& remote_candidate,
|
||||||
|
Port* origin_port,
|
||||||
|
bool readable) {
|
||||||
|
// Look for an existing connection with this remote address. If one is not
|
||||||
|
// found, then we can create a new connection for this address.
|
||||||
|
Connection* connection = port->GetConnection(remote_candidate.address());
|
||||||
|
if (connection != NULL) {
|
||||||
|
// It is not legal to try to change any of the parameters of an existing
|
||||||
|
// connection; however, the other side can send a duplicate candidate.
|
||||||
|
if (!remote_candidate.IsEquivalent(connection->remote_candidate())) {
|
||||||
|
LOG(INFO) << "Attempt to change a remote candidate";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Port::CandidateOrigin origin = GetOrigin(port, origin_port);
|
||||||
|
|
||||||
|
// Don't create connection if this is a candidate we received in a
|
||||||
|
// message and we are not allowed to make outgoing connections.
|
||||||
|
if (origin == cricket::Port::ORIGIN_MESSAGE && incoming_only_)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
connection = port->CreateConnection(remote_candidate, origin);
|
||||||
|
if (!connection)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
connections_.push_back(connection);
|
||||||
|
connection->SignalReadPacket.connect(
|
||||||
|
this, &P2PTransportChannel::OnReadPacket);
|
||||||
|
connection->SignalStateChange.connect(
|
||||||
|
this, &P2PTransportChannel::OnConnectionStateChange);
|
||||||
|
connection->SignalDestroyed.connect(
|
||||||
|
this, &P2PTransportChannel::OnConnectionDestroyed);
|
||||||
|
|
||||||
|
LOG_J(LS_INFO, this) << "Created connection with origin=" << origin << ", ("
|
||||||
|
<< connections_.size() << " total)";
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we are readable, it is because we are creating this in response to a
|
||||||
|
// ping from the other side. This will cause the state to become readable.
|
||||||
|
if (readable)
|
||||||
|
connection->ReceivedPing();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Maintain our remote candidate list, adding this new remote one.
|
||||||
|
void P2PTransportChannel::RememberRemoteCandidate(
|
||||||
|
const Candidate& remote_candidate, Port* origin_port) {
|
||||||
|
// Remove any candidates whose generation is older than this one. The
|
||||||
|
// presence of a new generation indicates that the old ones are not useful.
|
||||||
|
uint32 i = 0;
|
||||||
|
while (i < remote_candidates_.size()) {
|
||||||
|
if (remote_candidates_[i].generation() < remote_candidate.generation()) {
|
||||||
|
LOG(INFO) << "Pruning candidate from old generation: "
|
||||||
|
<< remote_candidates_[i].address().ToString();
|
||||||
|
remote_candidates_.erase(remote_candidates_.begin() + i);
|
||||||
|
} else {
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure this candidate is not a duplicate.
|
||||||
|
for (uint32 i = 0; i < remote_candidates_.size(); ++i) {
|
||||||
|
if (remote_candidates_[i].IsEquivalent(remote_candidate)) {
|
||||||
|
LOG(INFO) << "Duplicate candidate: "
|
||||||
|
<< remote_candidate.address().ToString();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try this candidate for all future ports.
|
||||||
|
remote_candidates_.push_back(RemoteCandidate(remote_candidate, origin_port));
|
||||||
|
|
||||||
|
// We have some candidates from the other side, we are now serious about
|
||||||
|
// this connection. Let's do the StartGetAllPorts thing.
|
||||||
|
if (!pinging_started_) {
|
||||||
|
pinging_started_ = true;
|
||||||
|
for (size_t i = 0; i < allocator_sessions_.size(); ++i) {
|
||||||
|
if (!allocator_sessions_[i]->IsGettingAllPorts())
|
||||||
|
allocator_sessions_[i]->StartGetAllPorts();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send data to the other side, using our best connection
|
||||||
|
int P2PTransportChannel::SendPacket(talk_base::Buffer* packet) {
|
||||||
|
#ifdef PLATFORM_CHROMIUM
|
||||||
|
if(worker_thread_ != talk_base::Thread::Current()) {
|
||||||
|
SendPacketParams* params = new SendPacketParams;
|
||||||
|
packet->TransferTo(¶ms->packet);
|
||||||
|
worker_thread_->Post(this, MSG_SENDPACKET, params);
|
||||||
|
return params->packet.length();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return SendPacket(packet->data(), packet->length());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send data to the other side, using our best connection
|
||||||
|
int P2PTransportChannel::SendPacket(const char *data, size_t len) {
|
||||||
|
// This can get called on any thread that is convenient to write from!
|
||||||
|
if (best_connection_ == NULL) {
|
||||||
|
error_ = EWOULDBLOCK;
|
||||||
|
return SOCKET_ERROR;
|
||||||
|
}
|
||||||
|
int sent = best_connection_->Send(data, len);
|
||||||
|
if (sent <= 0) {
|
||||||
|
ASSERT(sent < 0);
|
||||||
|
error_ = best_connection_->GetError();
|
||||||
|
}
|
||||||
|
return sent;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Begin allocate (or immediately re-allocate, if MSG_ALLOCATE pending)
|
||||||
|
void P2PTransportChannel::Allocate() {
|
||||||
|
CancelPendingAllocate();
|
||||||
|
// Time for a new allocator, lets make sure we have a signalling channel
|
||||||
|
// to communicate candidates through first.
|
||||||
|
waiting_for_signaling_ = true;
|
||||||
|
SignalRequestSignaling();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cancels the pending allocate, if any.
|
||||||
|
void P2PTransportChannel::CancelPendingAllocate() {
|
||||||
|
thread()->Clear(this, MSG_ALLOCATE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Monitor connection states
|
||||||
|
void P2PTransportChannel::UpdateConnectionStates() {
|
||||||
|
uint32 now = talk_base::Time();
|
||||||
|
|
||||||
|
// We need to copy the list of connections since some may delete themselves
|
||||||
|
// when we call UpdateState.
|
||||||
|
for (uint32 i = 0; i < connections_.size(); ++i)
|
||||||
|
connections_[i]->UpdateState(now);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare for best candidate sorting
|
||||||
|
void P2PTransportChannel::RequestSort() {
|
||||||
|
if (!sort_dirty_) {
|
||||||
|
worker_thread_->Post(this, MSG_SORT);
|
||||||
|
sort_dirty_ = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort the available connections to find the best one. We also monitor
|
||||||
|
// the number of available connections and the current state so that we
|
||||||
|
// can possibly kick off more allocators (for more connections).
|
||||||
|
void P2PTransportChannel::SortConnections() {
|
||||||
|
ASSERT(worker_thread_ == talk_base::Thread::Current());
|
||||||
|
|
||||||
|
// Make sure the connection states are up-to-date since this affects how they
|
||||||
|
// will be sorted.
|
||||||
|
UpdateConnectionStates();
|
||||||
|
|
||||||
|
// Any changes after this point will require a re-sort.
|
||||||
|
sort_dirty_ = false;
|
||||||
|
|
||||||
|
// Get a list of the networks that we are using.
|
||||||
|
std::set<talk_base::Network*> networks;
|
||||||
|
for (uint32 i = 0; i < connections_.size(); ++i)
|
||||||
|
networks.insert(connections_[i]->port()->network());
|
||||||
|
|
||||||
|
// Find the best alternative connection by sorting. It is important to note
|
||||||
|
// that amongst equal preference, writable connections, this will choose the
|
||||||
|
// one whose estimated latency is lowest. So it is the only one that we
|
||||||
|
// need to consider switching to.
|
||||||
|
|
||||||
|
ConnectionCompare cmp;
|
||||||
|
std::stable_sort(connections_.begin(), connections_.end(), cmp);
|
||||||
|
LOG(LS_VERBOSE) << "Sorting available connections:";
|
||||||
|
for (uint32 i = 0; i < connections_.size(); ++i) {
|
||||||
|
LOG(LS_VERBOSE) << connections_[i]->ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
Connection* top_connection = NULL;
|
||||||
|
if (connections_.size() > 0)
|
||||||
|
top_connection = connections_[0];
|
||||||
|
|
||||||
|
// If necessary, switch to the new choice.
|
||||||
|
if (ShouldSwitch(best_connection_, top_connection))
|
||||||
|
SwitchBestConnectionTo(top_connection);
|
||||||
|
|
||||||
|
// We can prune any connection for which there is a writable connection on
|
||||||
|
// the same network with better or equal prefences. We leave those with
|
||||||
|
// better preference just in case they become writable later (at which point,
|
||||||
|
// we would prune out the current best connection). We leave connections on
|
||||||
|
// other networks because they may not be using the same resources and they
|
||||||
|
// may represent very distinct paths over which we can switch.
|
||||||
|
std::set<talk_base::Network*>::iterator network;
|
||||||
|
for (network = networks.begin(); network != networks.end(); ++network) {
|
||||||
|
Connection* primier = GetBestConnectionOnNetwork(*network);
|
||||||
|
if (!primier || (primier->write_state() != Connection::STATE_WRITABLE))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (uint32 i = 0; i < connections_.size(); ++i) {
|
||||||
|
if ((connections_[i] != primier) &&
|
||||||
|
(connections_[i]->port()->network() == *network) &&
|
||||||
|
(CompareConnectionCandidates(primier, connections_[i]) >= 0)) {
|
||||||
|
connections_[i]->Prune();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Count the number of connections in the various states.
|
||||||
|
|
||||||
|
int writable = 0;
|
||||||
|
int write_connect = 0;
|
||||||
|
int write_timeout = 0;
|
||||||
|
|
||||||
|
for (uint32 i = 0; i < connections_.size(); ++i) {
|
||||||
|
switch (connections_[i]->write_state()) {
|
||||||
|
case Connection::STATE_WRITABLE:
|
||||||
|
++writable;
|
||||||
|
break;
|
||||||
|
case Connection::STATE_WRITE_CONNECT:
|
||||||
|
++write_connect;
|
||||||
|
break;
|
||||||
|
case Connection::STATE_WRITE_TIMEOUT:
|
||||||
|
++write_timeout;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ASSERT(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (writable > 0) {
|
||||||
|
HandleWritable();
|
||||||
|
} else if (write_connect > 0) {
|
||||||
|
HandleNotWritable();
|
||||||
|
} else {
|
||||||
|
HandleAllTimedOut();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the state of this channel. This method is called whenever the
|
||||||
|
// state of any connection changes, so this is a good place to do this.
|
||||||
|
UpdateChannelState();
|
||||||
|
|
||||||
|
// Notify of connection state change
|
||||||
|
SignalConnectionMonitor(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Track the best connection, and let listeners know
|
||||||
|
void P2PTransportChannel::SwitchBestConnectionTo(Connection* conn) {
|
||||||
|
// Note: if conn is NULL, the previous best_connection_ has been destroyed,
|
||||||
|
// so don't use it.
|
||||||
|
// use it.
|
||||||
|
Connection* old_best_connection = best_connection_;
|
||||||
|
best_connection_ = conn;
|
||||||
|
if (best_connection_) {
|
||||||
|
if (old_best_connection) {
|
||||||
|
LOG_J(LS_INFO, this) << "Previous best connection: "
|
||||||
|
<< old_best_connection->ToString();
|
||||||
|
}
|
||||||
|
LOG_J(LS_INFO, this) << "New best connection: "
|
||||||
|
<< best_connection_->ToString();
|
||||||
|
SignalRouteChange(this, best_connection_->remote_candidate());
|
||||||
|
} else {
|
||||||
|
LOG_J(LS_INFO, this) << "No best connection";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void P2PTransportChannel::UpdateChannelState() {
|
||||||
|
// The Handle* functions already set the writable state. We'll just double-
|
||||||
|
// check it here.
|
||||||
|
bool writable = ((best_connection_ != NULL) &&
|
||||||
|
(best_connection_->write_state() ==
|
||||||
|
Connection::STATE_WRITABLE));
|
||||||
|
ASSERT(writable == this->writable());
|
||||||
|
if (writable != this->writable())
|
||||||
|
LOG(LS_ERROR) << "UpdateChannelState: writable state mismatch";
|
||||||
|
|
||||||
|
bool readable = false;
|
||||||
|
for (uint32 i = 0; i < connections_.size(); ++i) {
|
||||||
|
if (connections_[i]->read_state() == Connection::STATE_READABLE)
|
||||||
|
readable = true;
|
||||||
|
}
|
||||||
|
set_readable(readable);
|
||||||
|
}
|
||||||
|
|
||||||
|
// We checked the status of our connections and we had at least one that
|
||||||
|
// was writable, go into the writable state.
|
||||||
|
void P2PTransportChannel::HandleWritable() {
|
||||||
|
//
|
||||||
|
// One or more connections writable!
|
||||||
|
//
|
||||||
|
if (!writable()) {
|
||||||
|
for (uint32 i = 0; i < allocator_sessions_.size(); ++i) {
|
||||||
|
if (allocator_sessions_[i]->IsGettingAllPorts()) {
|
||||||
|
allocator_sessions_[i]->StopGetAllPorts();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop further allocations.
|
||||||
|
CancelPendingAllocate();
|
||||||
|
}
|
||||||
|
|
||||||
|
// We're writable, obviously we aren't timed out
|
||||||
|
was_writable_ = true;
|
||||||
|
was_timed_out_ = false;
|
||||||
|
set_writable(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// We checked the status of our connections and we didn't have any that
|
||||||
|
// were writable, go into the connecting state (kick off a new allocator
|
||||||
|
// session).
|
||||||
|
void P2PTransportChannel::HandleNotWritable() {
|
||||||
|
//
|
||||||
|
// No connections are writable but not timed out!
|
||||||
|
//
|
||||||
|
if (was_writable_) {
|
||||||
|
// If we were writable, let's kick off an allocator session immediately
|
||||||
|
was_writable_ = false;
|
||||||
|
Allocate();
|
||||||
|
}
|
||||||
|
|
||||||
|
// We were connecting, obviously not ALL timed out.
|
||||||
|
was_timed_out_ = false;
|
||||||
|
set_writable(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// We checked the status of our connections and not only weren't they writable
|
||||||
|
// but they were also timed out, we really need a new allocator.
|
||||||
|
void P2PTransportChannel::HandleAllTimedOut() {
|
||||||
|
//
|
||||||
|
// No connections... all are timed out!
|
||||||
|
//
|
||||||
|
if (!was_timed_out_) {
|
||||||
|
// We weren't timed out before, so kick off an allocator now (we'll still
|
||||||
|
// be in the fully timed out state until the allocator actually gives back
|
||||||
|
// new ports)
|
||||||
|
Allocate();
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: we start was_timed_out_ in the true state so that we don't get
|
||||||
|
// another allocator created WHILE we are in the process of building up
|
||||||
|
// our first allocator.
|
||||||
|
was_timed_out_ = true;
|
||||||
|
was_writable_ = false;
|
||||||
|
set_writable(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we have a best connection, return it, otherwise return top one in the
|
||||||
|
// list (later we will mark it best).
|
||||||
|
Connection* P2PTransportChannel::GetBestConnectionOnNetwork(
|
||||||
|
talk_base::Network* network) {
|
||||||
|
// If the best connection is on this network, then it wins.
|
||||||
|
if (best_connection_ && (best_connection_->port()->network() == network))
|
||||||
|
return best_connection_;
|
||||||
|
|
||||||
|
// Otherwise, we return the top-most in sorted order.
|
||||||
|
for (uint32 i = 0; i < connections_.size(); ++i) {
|
||||||
|
if (connections_[i]->port()->network() == network)
|
||||||
|
return connections_[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle any queued up requests
|
||||||
|
void P2PTransportChannel::OnMessage(talk_base::Message *pmsg) {
|
||||||
|
if (pmsg->message_id == MSG_SORT)
|
||||||
|
OnSort();
|
||||||
|
else if (pmsg->message_id == MSG_PING)
|
||||||
|
OnPing();
|
||||||
|
else if (pmsg->message_id == MSG_ALLOCATE)
|
||||||
|
Allocate();
|
||||||
|
#ifdef PLATFORM_CHROMIUM
|
||||||
|
else if (pmsg->message_id == MSG_SENDPACKET) {
|
||||||
|
SendPacketParams* data = static_cast<SendPacketParams*>(pmsg->pdata);
|
||||||
|
SendPacket(&data->packet);
|
||||||
|
delete data; // because it is Posted
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
else
|
||||||
|
ASSERT(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle queued up sort request
|
||||||
|
void P2PTransportChannel::OnSort() {
|
||||||
|
// Resort the connections based on the new statistics.
|
||||||
|
SortConnections();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle queued up ping request
|
||||||
|
void P2PTransportChannel::OnPing() {
|
||||||
|
// Make sure the states of the connections are up-to-date (since this affects
|
||||||
|
// which ones are pingable).
|
||||||
|
UpdateConnectionStates();
|
||||||
|
|
||||||
|
// Find the oldest pingable connection and have it do a ping.
|
||||||
|
Connection* conn = FindNextPingableConnection();
|
||||||
|
if (conn)
|
||||||
|
conn->Ping(talk_base::Time());
|
||||||
|
|
||||||
|
// Post ourselves a message to perform the next ping.
|
||||||
|
uint32 delay = writable() ? WRITABLE_DELAY : UNWRITABLE_DELAY;
|
||||||
|
thread()->PostDelayed(delay, this, MSG_PING);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Is the connection in a state for us to even consider pinging the other side?
|
||||||
|
bool P2PTransportChannel::IsPingable(Connection* conn) {
|
||||||
|
// An unconnected connection cannot be written to at all, so pinging is out
|
||||||
|
// of the question.
|
||||||
|
if (!conn->connected())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (writable()) {
|
||||||
|
// If we are writable, then we only want to ping connections that could be
|
||||||
|
// better than this one, i.e., the ones that were not pruned.
|
||||||
|
return (conn->write_state() != Connection::STATE_WRITE_TIMEOUT);
|
||||||
|
} else {
|
||||||
|
// If we are not writable, then we need to try everything that might work.
|
||||||
|
// This includes both connections that do not have write timeout as well as
|
||||||
|
// ones that do not have read timeout. A connection could be readable but
|
||||||
|
// be in write-timeout if we pruned it before. Since the other side is
|
||||||
|
// still pinging it, it very well might still work.
|
||||||
|
return (conn->write_state() != Connection::STATE_WRITE_TIMEOUT) ||
|
||||||
|
(conn->read_state() != Connection::STATE_READ_TIMEOUT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the next pingable connection to ping. This will be the oldest
|
||||||
|
// pingable connection unless we have a writable connection that is past the
|
||||||
|
// maximum acceptable ping delay.
|
||||||
|
Connection* P2PTransportChannel::FindNextPingableConnection() {
|
||||||
|
uint32 now = talk_base::Time();
|
||||||
|
if (best_connection_ &&
|
||||||
|
(best_connection_->write_state() == Connection::STATE_WRITABLE) &&
|
||||||
|
(best_connection_->last_ping_sent()
|
||||||
|
+ MAX_CURRENT_WRITABLE_DELAY <= now)) {
|
||||||
|
return best_connection_;
|
||||||
|
}
|
||||||
|
|
||||||
|
Connection* oldest_conn = NULL;
|
||||||
|
uint32 oldest_time = 0xFFFFFFFF;
|
||||||
|
for (uint32 i = 0; i < connections_.size(); ++i) {
|
||||||
|
if (IsPingable(connections_[i])) {
|
||||||
|
if (connections_[i]->last_ping_sent() < oldest_time) {
|
||||||
|
oldest_time = connections_[i]->last_ping_sent();
|
||||||
|
oldest_conn = connections_[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return oldest_conn;
|
||||||
|
}
|
||||||
|
|
||||||
|
// return the number of "pingable" connections
|
||||||
|
uint32 P2PTransportChannel::NumPingableConnections() {
|
||||||
|
uint32 count = 0;
|
||||||
|
for (uint32 i = 0; i < connections_.size(); ++i) {
|
||||||
|
if (IsPingable(connections_[i]))
|
||||||
|
count += 1;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
// When a connection's state changes, we need to figure out who to use as
|
||||||
|
// the best connection again. It could have become usable, or become unusable.
|
||||||
|
void P2PTransportChannel::OnConnectionStateChange(Connection *connection) {
|
||||||
|
ASSERT(worker_thread_ == talk_base::Thread::Current());
|
||||||
|
|
||||||
|
// We have to unroll the stack before doing this because we may be changing
|
||||||
|
// the state of connections while sorting.
|
||||||
|
RequestSort();
|
||||||
|
}
|
||||||
|
|
||||||
|
// When a connection is removed, edit it out, and then update our best
|
||||||
|
// connection.
|
||||||
|
void P2PTransportChannel::OnConnectionDestroyed(Connection *connection) {
|
||||||
|
ASSERT(worker_thread_ == talk_base::Thread::Current());
|
||||||
|
|
||||||
|
// Note: the previous best_connection_ may be destroyed by now, so don't
|
||||||
|
// use it.
|
||||||
|
|
||||||
|
// Remove this connection from the list.
|
||||||
|
std::vector<Connection*>::iterator iter =
|
||||||
|
std::find(connections_.begin(), connections_.end(), connection);
|
||||||
|
ASSERT(iter != connections_.end());
|
||||||
|
connections_.erase(iter);
|
||||||
|
|
||||||
|
LOG_J(LS_INFO, this) << "Removed connection ("
|
||||||
|
<< static_cast<int>(connections_.size()) << " remaining)";
|
||||||
|
|
||||||
|
// If this is currently the best connection, then we need to pick a new one.
|
||||||
|
// The call to SortConnections will pick a new one. It looks at the current
|
||||||
|
// best connection in order to avoid switching between fairly similar ones.
|
||||||
|
// Since this connection is no longer an option, we can just set best to NULL
|
||||||
|
// and re-choose a best assuming that there was no best connection.
|
||||||
|
if (best_connection_ == connection) {
|
||||||
|
SwitchBestConnectionTo(NULL);
|
||||||
|
RequestSort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// When a port is destroyed remove it from our list of ports to use for
|
||||||
|
// connection attempts.
|
||||||
|
void P2PTransportChannel::OnPortDestroyed(Port* port) {
|
||||||
|
ASSERT(worker_thread_ == talk_base::Thread::Current());
|
||||||
|
|
||||||
|
// Remove this port from the list (if we didn't drop it already).
|
||||||
|
std::vector<Port*>::iterator iter =
|
||||||
|
std::find(ports_.begin(), ports_.end(), port);
|
||||||
|
if (iter != ports_.end())
|
||||||
|
ports_.erase(iter);
|
||||||
|
|
||||||
|
LOG(INFO) << "Removed port from p2p socket: "
|
||||||
|
<< static_cast<int>(ports_.size()) << " remaining";
|
||||||
|
}
|
||||||
|
|
||||||
|
// We data is available, let listeners know
|
||||||
|
void P2PTransportChannel::OnReadPacket(Connection *connection,
|
||||||
|
const char *data, size_t len) {
|
||||||
|
ASSERT(worker_thread_ == talk_base::Thread::Current());
|
||||||
|
|
||||||
|
// Let the client know of an incoming packet
|
||||||
|
|
||||||
|
SignalReadPacket(this, data, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set options on ourselves is simply setting options on all of our available
|
||||||
|
// port objects.
|
||||||
|
int P2PTransportChannel::SetOption(talk_base::Socket::Option opt, int value) {
|
||||||
|
OptionMap::iterator it = options_.find(opt);
|
||||||
|
if (it == options_.end()) {
|
||||||
|
options_.insert(std::make_pair(opt, value));
|
||||||
|
} else if (it->second == value) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
it->second = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint32 i = 0; i < ports_.size(); ++i) {
|
||||||
|
int val = ports_[i]->SetOption(opt, value);
|
||||||
|
if (val < 0) {
|
||||||
|
// Because this also occurs deferred, probably no point in reporting an
|
||||||
|
// error
|
||||||
|
LOG(WARNING) << "SetOption(" << opt << ", " << value << ") failed: "
|
||||||
|
<< ports_[i]->GetError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// When the signalling channel is ready, we can really kick off the allocator
|
||||||
|
void P2PTransportChannel::OnSignalingReady() {
|
||||||
|
if (waiting_for_signaling_) {
|
||||||
|
waiting_for_signaling_ = false;
|
||||||
|
AddAllocatorSession(allocator_->CreateSession(name(), content_type()));
|
||||||
|
thread()->PostDelayed(kAllocatePeriod, this, MSG_ALLOCATE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace cricket
|
||||||
@ -0,0 +1,169 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// P2PTransportChannel wraps up the state management of the connection between
|
||||||
|
// two P2P clients. Clients have candidate ports for connecting, and
|
||||||
|
// connections which are combinations of candidates from each end (Alice and
|
||||||
|
// Bob each have candidates, one candidate from Alice and one candidate from
|
||||||
|
// Bob are used to make a connection, repeat to make many connections).
|
||||||
|
//
|
||||||
|
// When all of the available connections become invalid (non-writable), we
|
||||||
|
// kick off a process of determining more candidates and more connections.
|
||||||
|
//
|
||||||
|
#ifndef TALK_P2P_BASE_P2PTRANSPORTCHANNEL_H_
|
||||||
|
#define TALK_P2P_BASE_P2PTRANSPORTCHANNEL_H_
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "talk/base/sigslot.h"
|
||||||
|
#include "talk/p2p/base/candidate.h"
|
||||||
|
#include "talk/p2p/base/port.h"
|
||||||
|
#include "talk/p2p/base/portallocator.h"
|
||||||
|
#include "talk/p2p/base/transport.h"
|
||||||
|
#include "talk/p2p/base/transportchannelimpl.h"
|
||||||
|
#include "talk/p2p/base/p2ptransport.h"
|
||||||
|
|
||||||
|
namespace cricket {
|
||||||
|
|
||||||
|
// Adds the port on which the candidate originated.
|
||||||
|
class RemoteCandidate : public Candidate {
|
||||||
|
public:
|
||||||
|
RemoteCandidate(const Candidate& c, Port* origin_port)
|
||||||
|
: Candidate(c), origin_port_(origin_port) {}
|
||||||
|
|
||||||
|
Port* origin_port() { return origin_port_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
Port* origin_port_;
|
||||||
|
};
|
||||||
|
|
||||||
|
// P2PTransportChannel manages the candidates and connection process to keep
|
||||||
|
// two P2P clients connected to each other.
|
||||||
|
class P2PTransportChannel : public TransportChannelImpl,
|
||||||
|
public talk_base::MessageHandler {
|
||||||
|
public:
|
||||||
|
P2PTransportChannel(const std::string &name,
|
||||||
|
const std::string &content_type,
|
||||||
|
P2PTransport* transport,
|
||||||
|
PortAllocator *allocator);
|
||||||
|
virtual ~P2PTransportChannel();
|
||||||
|
|
||||||
|
// From TransportChannelImpl:
|
||||||
|
virtual Transport* GetTransport() { return transport_; }
|
||||||
|
virtual void Connect();
|
||||||
|
virtual void Reset();
|
||||||
|
virtual void OnSignalingReady();
|
||||||
|
|
||||||
|
// From TransportChannel:
|
||||||
|
virtual int SendPacket(talk_base::Buffer* packet);
|
||||||
|
virtual int SendPacket(const char *data, size_t len);
|
||||||
|
virtual int SetOption(talk_base::Socket::Option opt, int value);
|
||||||
|
virtual int GetError() { return error_; }
|
||||||
|
|
||||||
|
// This hack is here to allow the SocketMonitor to downcast to the
|
||||||
|
// P2PTransportChannel safely.
|
||||||
|
virtual P2PTransportChannel* GetP2PChannel() { return this; }
|
||||||
|
|
||||||
|
// These are used by the connection monitor.
|
||||||
|
sigslot::signal1<P2PTransportChannel*> SignalConnectionMonitor;
|
||||||
|
const std::vector<Connection *>& connections() const { return connections_; }
|
||||||
|
Connection* best_connection() const { return best_connection_; }
|
||||||
|
|
||||||
|
void set_incoming_only(bool value) { incoming_only_ = value; }
|
||||||
|
|
||||||
|
// Handler for internal messages.
|
||||||
|
virtual void OnMessage(talk_base::Message *pmsg);
|
||||||
|
|
||||||
|
virtual void OnCandidate(const Candidate& candidate);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void Allocate();
|
||||||
|
void CancelPendingAllocate();
|
||||||
|
void UpdateConnectionStates();
|
||||||
|
void RequestSort();
|
||||||
|
void SortConnections();
|
||||||
|
void SwitchBestConnectionTo(Connection* conn);
|
||||||
|
void UpdateChannelState();
|
||||||
|
void HandleWritable();
|
||||||
|
void HandleNotWritable();
|
||||||
|
void HandleAllTimedOut();
|
||||||
|
Connection* GetBestConnectionOnNetwork(talk_base::Network* network);
|
||||||
|
bool CreateConnections(const Candidate &remote_candidate, Port* origin_port,
|
||||||
|
bool readable);
|
||||||
|
bool CreateConnection(Port* port, const Candidate& remote_candidate,
|
||||||
|
Port* origin_port, bool readable);
|
||||||
|
void RememberRemoteCandidate(const Candidate& remote_candidate,
|
||||||
|
Port* origin_port);
|
||||||
|
void OnUnknownAddress(Port *port, const talk_base::SocketAddress &addr,
|
||||||
|
StunMessage *stun_msg,
|
||||||
|
const std::string &remote_username);
|
||||||
|
void OnPortReady(PortAllocatorSession *session, Port* port);
|
||||||
|
void OnCandidatesReady(PortAllocatorSession *session,
|
||||||
|
const std::vector<Candidate>& candidates);
|
||||||
|
void OnConnectionStateChange(Connection *connection);
|
||||||
|
void OnConnectionDestroyed(Connection *connection);
|
||||||
|
void OnPortDestroyed(Port* port);
|
||||||
|
void OnReadPacket(Connection *connection, const char *data, size_t len);
|
||||||
|
void OnSort();
|
||||||
|
void OnPing();
|
||||||
|
bool IsPingable(Connection* conn);
|
||||||
|
Connection* FindNextPingableConnection();
|
||||||
|
uint32 NumPingableConnections();
|
||||||
|
PortAllocatorSession* allocator_session() {
|
||||||
|
return allocator_sessions_.back();
|
||||||
|
}
|
||||||
|
void AddAllocatorSession(PortAllocatorSession* session);
|
||||||
|
|
||||||
|
talk_base::Thread* thread() const { return worker_thread_; }
|
||||||
|
|
||||||
|
P2PTransport* transport_;
|
||||||
|
PortAllocator *allocator_;
|
||||||
|
talk_base::Thread *worker_thread_;
|
||||||
|
bool incoming_only_;
|
||||||
|
bool waiting_for_signaling_;
|
||||||
|
int error_;
|
||||||
|
std::vector<PortAllocatorSession*> allocator_sessions_;
|
||||||
|
std::vector<Port *> ports_;
|
||||||
|
std::vector<Connection *> connections_;
|
||||||
|
Connection *best_connection_;
|
||||||
|
std::vector<RemoteCandidate> remote_candidates_;
|
||||||
|
// indicates whether StartGetAllCandidates has been called
|
||||||
|
bool pinging_started_;
|
||||||
|
bool sort_dirty_; // indicates whether another sort is needed right now
|
||||||
|
bool was_writable_;
|
||||||
|
bool was_timed_out_;
|
||||||
|
typedef std::map<talk_base::Socket::Option, int> OptionMap;
|
||||||
|
OptionMap options_;
|
||||||
|
|
||||||
|
DISALLOW_EVIL_CONSTRUCTORS(P2PTransportChannel);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace cricket
|
||||||
|
|
||||||
|
#endif // TALK_P2P_BASE_P2PTRANSPORTCHANNEL_H_
|
||||||
546
third_party_mods/libjingle/source/talk/p2p/base/session.h
Normal file
546
third_party_mods/libjingle/source/talk/p2p/base/session.h
Normal file
@ -0,0 +1,546 @@
|
|||||||
|
/*
|
||||||
|
* 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 TALK_P2P_BASE_SESSION_H_
|
||||||
|
#define TALK_P2P_BASE_SESSION_H_
|
||||||
|
|
||||||
|
#include <list>
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "talk/p2p/base/sessionmessages.h"
|
||||||
|
#include "talk/p2p/base/sessionmanager.h"
|
||||||
|
#include "talk/base/socketaddress.h"
|
||||||
|
#include "talk/p2p/base/sessionclient.h"
|
||||||
|
#include "talk/p2p/base/parsing.h"
|
||||||
|
#include "talk/p2p/base/port.h"
|
||||||
|
#include "talk/xmllite/xmlelement.h"
|
||||||
|
#include "talk/xmpp/constants.h"
|
||||||
|
|
||||||
|
namespace cricket {
|
||||||
|
|
||||||
|
class P2PTransportChannel;
|
||||||
|
class Transport;
|
||||||
|
class TransportChannel;
|
||||||
|
class TransportChannelProxy;
|
||||||
|
class TransportChannelImpl;
|
||||||
|
|
||||||
|
// 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 {
|
||||||
|
};
|
||||||
|
|
||||||
|
// Bundles a Transport and ChannelMap together. ChannelMap is used to
|
||||||
|
// create transport channels before receiving or sending a session
|
||||||
|
// initiate, and for speculatively connecting channels. Previously, a
|
||||||
|
// session had one ChannelMap and transport. Now, with multiple
|
||||||
|
// transports per session, we need multiple ChannelMaps as well.
|
||||||
|
class TransportProxy {
|
||||||
|
public:
|
||||||
|
TransportProxy(const std::string& content_name, Transport* transport)
|
||||||
|
: content_name_(content_name),
|
||||||
|
transport_(transport),
|
||||||
|
state_(STATE_INIT),
|
||||||
|
sent_candidates_(false) {}
|
||||||
|
~TransportProxy();
|
||||||
|
|
||||||
|
std::string content_name() const { return content_name_; }
|
||||||
|
Transport* impl() const { return transport_; }
|
||||||
|
std::string type() const;
|
||||||
|
bool negotiated() const { return state_ == STATE_NEGOTIATED; }
|
||||||
|
const Candidates& sent_candidates() const { return sent_candidates_; }
|
||||||
|
|
||||||
|
TransportChannel* GetChannel(const std::string& name);
|
||||||
|
TransportChannel* CreateChannel(const std::string& name,
|
||||||
|
const std::string& content_type);
|
||||||
|
void DestroyChannel(const std::string& name);
|
||||||
|
void AddSentCandidates(const Candidates& candidates);
|
||||||
|
void ClearSentCandidates() { sent_candidates_.clear(); }
|
||||||
|
void SpeculativelyConnectChannels();
|
||||||
|
void CompleteNegotiation();
|
||||||
|
|
||||||
|
private:
|
||||||
|
enum TransportState {
|
||||||
|
STATE_INIT,
|
||||||
|
STATE_CONNECTING,
|
||||||
|
STATE_NEGOTIATED
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::map<std::string, TransportChannelProxy*> ChannelMap;
|
||||||
|
|
||||||
|
TransportChannelProxy* GetProxy(const std::string& name);
|
||||||
|
TransportChannelImpl* GetOrCreateImpl(const std::string& name,
|
||||||
|
const std::string& content_type);
|
||||||
|
void SetProxyImpl(const std::string& name, TransportChannelProxy* proxy);
|
||||||
|
|
||||||
|
std::string content_name_;
|
||||||
|
Transport* transport_;
|
||||||
|
TransportState state_;
|
||||||
|
ChannelMap channels_;
|
||||||
|
Candidates sent_candidates_;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::map<std::string, TransportProxy*> TransportMap;
|
||||||
|
|
||||||
|
// TODO: Consider simplifying the dependency from Voice/VideoChannel
|
||||||
|
// on Session. Right now the Channel class requires a BaseSession, but it only
|
||||||
|
// uses CreateChannel/DestroyChannel. Perhaps something like a
|
||||||
|
// TransportChannelFactory could be hoisted up out of BaseSession, or maybe
|
||||||
|
// the transports could be passed in directly.
|
||||||
|
|
||||||
|
// A BaseSession manages general session state. This includes negotiation
|
||||||
|
// of both the application-level and network-level protocols: the former
|
||||||
|
// defines what will be sent and the latter defines how it will be sent. Each
|
||||||
|
// network-level protocol is represented by a Transport object. Each Transport
|
||||||
|
// participates in the network-level negotiation. The individual streams of
|
||||||
|
// packets are represented by TransportChannels. The application-level protocol
|
||||||
|
// is represented by SessionDecription objects.
|
||||||
|
class BaseSession : public sigslot::has_slots<>,
|
||||||
|
public talk_base::MessageHandler {
|
||||||
|
public:
|
||||||
|
enum State {
|
||||||
|
STATE_INIT = 0,
|
||||||
|
STATE_SENTINITIATE, // sent initiate, waiting for Accept or Reject
|
||||||
|
STATE_RECEIVEDINITIATE, // received an initiate. Call Accept or Reject
|
||||||
|
STATE_SENTACCEPT, // sent accept. begin connecting transport
|
||||||
|
STATE_RECEIVEDACCEPT, // received accept. begin connecting transport
|
||||||
|
STATE_SENTMODIFY, // sent modify, waiting for Accept or Reject
|
||||||
|
STATE_RECEIVEDMODIFY, // received modify, call Accept or Reject
|
||||||
|
STATE_SENTREJECT, // sent reject after receiving initiate
|
||||||
|
STATE_RECEIVEDREJECT, // received reject after sending initiate
|
||||||
|
STATE_SENTREDIRECT, // sent direct after receiving initiate
|
||||||
|
STATE_SENTTERMINATE, // sent terminate (any time / either side)
|
||||||
|
STATE_RECEIVEDTERMINATE, // received terminate (any time / either side)
|
||||||
|
STATE_INPROGRESS, // session accepted and in progress
|
||||||
|
STATE_DEINIT, // session is being destroyed
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Error {
|
||||||
|
ERROR_NONE = 0, // no error
|
||||||
|
ERROR_TIME = 1, // no response to signaling
|
||||||
|
ERROR_RESPONSE = 2, // error during signaling
|
||||||
|
ERROR_NETWORK = 3, // network error, could not allocate network resources
|
||||||
|
ERROR_CONTENT = 4, // channel errors in SetLocalContent/SetRemoteContent
|
||||||
|
};
|
||||||
|
|
||||||
|
explicit BaseSession(talk_base::Thread *signaling_thread);
|
||||||
|
virtual ~BaseSession();
|
||||||
|
|
||||||
|
// Updates the state, signaling if necessary.
|
||||||
|
void SetState(State state);
|
||||||
|
|
||||||
|
// Updates the error state, signaling if necessary.
|
||||||
|
virtual void SetError(Error error);
|
||||||
|
|
||||||
|
// Handles messages posted to us.
|
||||||
|
virtual void OnMessage(talk_base::Message *pmsg);
|
||||||
|
|
||||||
|
// Returns the current state of the session. See the enum above for details.
|
||||||
|
// Each time the state changes, we will fire this signal.
|
||||||
|
State state() const { return state_; }
|
||||||
|
sigslot::signal2<BaseSession *, State> SignalState;
|
||||||
|
|
||||||
|
// Returns the last error in the session. See the enum above for details.
|
||||||
|
// Each time the an error occurs, we will fire this signal.
|
||||||
|
Error error() const { return error_; }
|
||||||
|
sigslot::signal2<BaseSession *, Error> SignalError;
|
||||||
|
|
||||||
|
sigslot::signal1<TransportChannel*> SignalWritableState;
|
||||||
|
sigslot::signal3<TransportChannel*, const char*, size_t> SignalReadPacket;
|
||||||
|
|
||||||
|
|
||||||
|
// Creates a new channel with the given names. This method may be called
|
||||||
|
// immediately after creating the session. However, the actual
|
||||||
|
// implementation may not be fixed until transport negotiation completes.
|
||||||
|
// This will usually be called from the worker thread, but that
|
||||||
|
// shouldn't be an issue since the main thread will be blocked in
|
||||||
|
// Send when doing so.
|
||||||
|
virtual TransportChannel* CreateChannel(const std::string& content_name,
|
||||||
|
const std::string& channel_name) = 0;
|
||||||
|
|
||||||
|
// Returns the channel with the given names.
|
||||||
|
virtual TransportChannel* GetChannel(const std::string& content_name,
|
||||||
|
const std::string& channel_name) = 0;
|
||||||
|
|
||||||
|
// Destroys the channel with the given names.
|
||||||
|
// This will usually be called from the worker thread, but that
|
||||||
|
// shouldn't be an issue since the main thread will be blocked in
|
||||||
|
// Send when doing so.
|
||||||
|
virtual void DestroyChannel(const std::string& content_name,
|
||||||
|
const std::string& channel_name) = 0;
|
||||||
|
|
||||||
|
// Invoked when we notice that there is no matching channel on our peer.
|
||||||
|
sigslot::signal2<Session*, const std::string&> SignalChannelGone;
|
||||||
|
|
||||||
|
// Returns the application-level description given by our client.
|
||||||
|
// If we are the recipient, this will be NULL until we send an accept.
|
||||||
|
const SessionDescription* local_description() const {
|
||||||
|
return local_description_;
|
||||||
|
}
|
||||||
|
// Takes ownership of SessionDescription*
|
||||||
|
bool set_local_description(const SessionDescription* sdesc) {
|
||||||
|
if (sdesc != local_description_) {
|
||||||
|
delete local_description_;
|
||||||
|
local_description_ = sdesc;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the application-level description given by the other client.
|
||||||
|
// If we are the initiator, this will be NULL until we receive an accept.
|
||||||
|
const SessionDescription* remote_description() const {
|
||||||
|
return remote_description_;
|
||||||
|
}
|
||||||
|
// Takes ownership of SessionDescription*
|
||||||
|
bool set_remote_description(const SessionDescription* sdesc) {
|
||||||
|
if (sdesc != remote_description_) {
|
||||||
|
delete remote_description_;
|
||||||
|
remote_description_ = sdesc;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// When we receive an initiate, we create a session in the
|
||||||
|
// RECEIVEDINITIATE state and respond by accepting or rejecting.
|
||||||
|
// Takes ownership of session description.
|
||||||
|
virtual bool Accept(const SessionDescription* sdesc) = 0;
|
||||||
|
virtual bool Reject(const std::string& reason) = 0;
|
||||||
|
bool Terminate() {
|
||||||
|
return TerminateWithReason(STR_TERMINATE_SUCCESS);
|
||||||
|
}
|
||||||
|
virtual bool TerminateWithReason(const std::string& reason) = 0;
|
||||||
|
|
||||||
|
// The worker thread used by the session manager
|
||||||
|
virtual talk_base::Thread *worker_thread() = 0;
|
||||||
|
|
||||||
|
talk_base::Thread *signaling_thread() {
|
||||||
|
return signaling_thread_;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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; }
|
||||||
|
|
||||||
|
const std::string& id() const { return sid_; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
State state_;
|
||||||
|
Error error_;
|
||||||
|
const SessionDescription* local_description_;
|
||||||
|
const SessionDescription* remote_description_;
|
||||||
|
std::string sid_;
|
||||||
|
// We don't use buzz::Jid because changing to buzz:Jid here has a
|
||||||
|
// cascading effect that requires an enormous number places to
|
||||||
|
// change to buzz::Jid as well.
|
||||||
|
std::string local_name_;
|
||||||
|
std::string remote_name_;
|
||||||
|
talk_base::Thread *signaling_thread_;
|
||||||
|
};
|
||||||
|
|
||||||
|
// A specific Session created by the SessionManager, using XMPP for protocol.
|
||||||
|
class Session : public BaseSession {
|
||||||
|
public:
|
||||||
|
// Returns the manager that created and owns this session.
|
||||||
|
SessionManager* session_manager() const { return session_manager_; }
|
||||||
|
|
||||||
|
// the worker thread used by the session manager
|
||||||
|
talk_base::Thread *worker_thread() {
|
||||||
|
return session_manager_->worker_thread();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the XML namespace identifying the type of this session.
|
||||||
|
const std::string& content_type() const { return content_type_; }
|
||||||
|
|
||||||
|
// Returns the client that is handling the application data of this session.
|
||||||
|
SessionClient* client() const { return client_; }
|
||||||
|
|
||||||
|
SignalingProtocol current_protocol() const { return current_protocol_; }
|
||||||
|
|
||||||
|
void set_current_protocol(SignalingProtocol protocol) {
|
||||||
|
current_protocol_ = protocol;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Indicates whether we initiated this session.
|
||||||
|
bool initiator() const { return initiator_; }
|
||||||
|
|
||||||
|
const SessionDescription* initiator_description() const {
|
||||||
|
if (initiator_) {
|
||||||
|
return local_description_;
|
||||||
|
} else {
|
||||||
|
return remote_description_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fired whenever we receive a terminate message along with a reason
|
||||||
|
sigslot::signal2<Session*, const std::string&> SignalReceivedTerminateReason;
|
||||||
|
|
||||||
|
void set_allow_local_ips(bool allow);
|
||||||
|
|
||||||
|
// Returns the transport that has been negotiated or NULL if
|
||||||
|
// negotiation is still in progress.
|
||||||
|
Transport* GetTransport(const std::string& content_name);
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
virtual bool Accept(const SessionDescription* sdesc);
|
||||||
|
virtual bool Reject(const std::string& reason);
|
||||||
|
virtual bool TerminateWithReason(const std::string& reason);
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
sigslot::signal2<Session*, const buzz::XmlElement*> SignalInfoMessage;
|
||||||
|
|
||||||
|
// Maps passed to serialization functions.
|
||||||
|
TransportParserMap GetTransportParsers();
|
||||||
|
ContentParserMap GetContentParsers();
|
||||||
|
|
||||||
|
// Creates a new channel with the given names. This method may be called
|
||||||
|
// immediately after creating the session. However, the actual
|
||||||
|
// implementation may not be fixed until transport negotiation completes.
|
||||||
|
virtual TransportChannel* CreateChannel(const std::string& content_name,
|
||||||
|
const std::string& channel_name);
|
||||||
|
|
||||||
|
// Returns the channel with the given names.
|
||||||
|
virtual TransportChannel* GetChannel(const std::string& content_name,
|
||||||
|
const std::string& channel_name);
|
||||||
|
|
||||||
|
// Destroys the channel with the given names.
|
||||||
|
virtual void DestroyChannel(const std::string& content_name,
|
||||||
|
const std::string& channel_name);
|
||||||
|
|
||||||
|
// Updates the error state, signaling if necessary.
|
||||||
|
virtual void SetError(Error error);
|
||||||
|
|
||||||
|
// Handles messages posted to us.
|
||||||
|
virtual void OnMessage(talk_base::Message *pmsg);
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Creates or destroys a session. (These are called only SessionManager.)
|
||||||
|
Session(SessionManager *session_manager,
|
||||||
|
const std::string& local_name, const std::string& initiator_name,
|
||||||
|
const std::string& sid, const std::string& content_type,
|
||||||
|
SessionClient* client);
|
||||||
|
~Session();
|
||||||
|
|
||||||
|
// Get a TransportProxy by content_name or transport. NULL if not found.
|
||||||
|
TransportProxy* GetTransportProxy(const std::string& content_name);
|
||||||
|
TransportProxy* GetTransportProxy(const Transport* transport);
|
||||||
|
TransportProxy* GetFirstTransportProxy();
|
||||||
|
// TransportProxy is owned by session. Return proxy just for convenience.
|
||||||
|
TransportProxy* GetOrCreateTransportProxy(const std::string& content_name);
|
||||||
|
// For each transport info, create a transport proxy. Can fail for
|
||||||
|
// incompatible transport types.
|
||||||
|
bool CreateTransportProxies(const TransportInfos& tinfos,
|
||||||
|
SessionError* error);
|
||||||
|
void SpeculativelyConnectAllTransportChannels();
|
||||||
|
bool OnRemoteCandidates(const TransportInfos& tinfos,
|
||||||
|
ParseError* error);
|
||||||
|
// Returns a TransportInfo without candidates for each content name.
|
||||||
|
// Uses the transport_type_ of the session.
|
||||||
|
TransportInfos GetEmptyTransportInfos(const ContentInfos& contents) const;
|
||||||
|
|
||||||
|
// Called when the first channel of a transport begins connecting. We use
|
||||||
|
// this to start a timer, to make sure that the connection completes in a
|
||||||
|
// reasonable amount of time.
|
||||||
|
void OnTransportConnecting(Transport* transport);
|
||||||
|
|
||||||
|
// Called when a transport changes its writable state. We track this to make
|
||||||
|
// sure that the transport becomes writable within a reasonable amount of
|
||||||
|
// time. If this does not occur, we signal an error.
|
||||||
|
void OnTransportWritable(Transport* transport);
|
||||||
|
|
||||||
|
// Called when a transport requests signaling.
|
||||||
|
void OnTransportRequestSignaling(Transport* transport);
|
||||||
|
|
||||||
|
// Called when a transport signals that it has a message to send. Note that
|
||||||
|
// these messages are just the transport part of the stanza; they need to be
|
||||||
|
// wrapped in the appropriate session tags.
|
||||||
|
void OnTransportCandidatesReady(Transport* transport,
|
||||||
|
const Candidates& candidates);
|
||||||
|
|
||||||
|
// Called when a transport signals that it found an error in an incoming
|
||||||
|
// message.
|
||||||
|
void OnTransportSendError(Transport* transport,
|
||||||
|
const buzz::XmlElement* stanza,
|
||||||
|
const buzz::QName& name,
|
||||||
|
const std::string& type,
|
||||||
|
const std::string& text,
|
||||||
|
const buzz::XmlElement* extra_info);
|
||||||
|
|
||||||
|
// Called when we notice that one of our local channels has no peer, so it
|
||||||
|
// should be destroyed.
|
||||||
|
void OnTransportChannelGone(Transport* transport, const std::string& name);
|
||||||
|
|
||||||
|
// When the session needs to send signaling messages, it beings by requesting
|
||||||
|
// signaling. The client should handle this by calling OnSignalingReady once
|
||||||
|
// it is ready to send the messages.
|
||||||
|
// (These are called only by SessionManager.)
|
||||||
|
sigslot::signal1<Session*> SignalRequestSignaling;
|
||||||
|
void OnSignalingReady();
|
||||||
|
|
||||||
|
// 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 ResendAllTransportInfoMessages(SessionError* error);
|
||||||
|
|
||||||
|
// Both 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);
|
||||||
|
// When passing an action, may be Hybrid protocol.
|
||||||
|
template <typename Action>
|
||||||
|
bool SendMessage(ActionType type, const Action& action,
|
||||||
|
SessionError* error);
|
||||||
|
|
||||||
|
// Helper methods to write the session message stanza.
|
||||||
|
template <typename Action>
|
||||||
|
bool WriteActionMessage(ActionType type, const Action& action,
|
||||||
|
buzz::XmlElement* stanza, WriteError* error);
|
||||||
|
template <typename Action>
|
||||||
|
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<Session *, const buzz::XmlElement*> SignalOutgoingMessage;
|
||||||
|
void OnIncomingMessage(const SessionMessage& msg);
|
||||||
|
|
||||||
|
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<BaseSession*,
|
||||||
|
const buzz::XmlElement*,
|
||||||
|
const buzz::QName&,
|
||||||
|
const std::string&,
|
||||||
|
const std::string&,
|
||||||
|
const buzz::XmlElement*> 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 OnUpdateMessage(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 initiator_;
|
||||||
|
std::string initiator_name_;
|
||||||
|
std::string content_type_;
|
||||||
|
SessionClient* client_;
|
||||||
|
std::string transport_type_;
|
||||||
|
TransportParser* transport_parser_;
|
||||||
|
// This is transport-specific but required so much by unit tests
|
||||||
|
// that it's much easier to put it here.
|
||||||
|
bool allow_local_ips_;
|
||||||
|
TransportMap transports_;
|
||||||
|
// Keeps track of what protocol we are speaking.
|
||||||
|
SignalingProtocol current_protocol_;
|
||||||
|
|
||||||
|
friend class SessionManager; // For access to constructor, destructor,
|
||||||
|
// and signaling related methods.
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace cricket
|
||||||
|
|
||||||
|
#endif // TALK_P2P_BASE_SESSION_H_
|
||||||
@ -0,0 +1,114 @@
|
|||||||
|
/*
|
||||||
|
* 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 TALK_P2P_BASE_TRANSPORTCHANNEL_H_
|
||||||
|
#define TALK_P2P_BASE_TRANSPORTCHANNEL_H_
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include "talk/base/basictypes.h"
|
||||||
|
#include "talk/base/sigslot.h"
|
||||||
|
#include "talk/base/socket.h"
|
||||||
|
|
||||||
|
namespace talk_base {
|
||||||
|
class Buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace cricket {
|
||||||
|
|
||||||
|
class Candidate;
|
||||||
|
class P2PTransportChannel;
|
||||||
|
|
||||||
|
// A TransportChannel represents one logical stream of packets that are sent
|
||||||
|
// between the two sides of a session.
|
||||||
|
class TransportChannel: public sigslot::has_slots<> {
|
||||||
|
public:
|
||||||
|
TransportChannel(const std::string& name, const std::string &content_type)
|
||||||
|
: name_(name), content_type_(content_type),
|
||||||
|
readable_(false), writable_(false) {}
|
||||||
|
virtual ~TransportChannel() {}
|
||||||
|
|
||||||
|
// Returns the name of this channel.
|
||||||
|
const std::string& name() const { return name_; }
|
||||||
|
const std::string& content_type() const { return content_type_; }
|
||||||
|
|
||||||
|
// Returns the readable and states of this channel. Each time one of these
|
||||||
|
// states changes, a signal is raised. These states are aggregated by the
|
||||||
|
// TransportManager.
|
||||||
|
bool readable() const { return readable_; }
|
||||||
|
bool writable() const { return writable_; }
|
||||||
|
sigslot::signal1<TransportChannel*> SignalReadableState;
|
||||||
|
sigslot::signal1<TransportChannel*> SignalWritableState;
|
||||||
|
|
||||||
|
virtual int SendPacket(talk_base::Buffer* packet) = 0;
|
||||||
|
// Attempts to send the given packet. The return value is < 0 on failure.
|
||||||
|
virtual int SendPacket(const char *data, size_t len) = 0;
|
||||||
|
|
||||||
|
// Sets a socket option on this channel. Note that not all options are
|
||||||
|
// supported by all transport types.
|
||||||
|
virtual int SetOption(talk_base::Socket::Option opt, int value) = 0;
|
||||||
|
|
||||||
|
// Returns the most recent error that occurred on this channel.
|
||||||
|
virtual int GetError() = 0;
|
||||||
|
|
||||||
|
// This hack is here to allow the SocketMonitor to downcast to the
|
||||||
|
// P2PTransportChannel safely.
|
||||||
|
// TODO: Generalize network monitoring.
|
||||||
|
virtual P2PTransportChannel* GetP2PChannel() { return NULL; }
|
||||||
|
|
||||||
|
// Signalled each time a packet is received on this channel.
|
||||||
|
sigslot::signal3<TransportChannel*, const char*, size_t> SignalReadPacket;
|
||||||
|
|
||||||
|
// This signal occurs when there is a change in the way that packets are
|
||||||
|
// being routed, i.e. to a different remote location. The candidate
|
||||||
|
// indicates where and how we are currently sending media.
|
||||||
|
sigslot::signal2<TransportChannel*, const Candidate&> SignalRouteChange;
|
||||||
|
|
||||||
|
// Invoked when the channel is being destroyed.
|
||||||
|
sigslot::signal1<TransportChannel*> SignalDestroyed;
|
||||||
|
|
||||||
|
// Debugging description of this transport channel.
|
||||||
|
std::string ToString() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// Sets the readable state, signaling if necessary.
|
||||||
|
void set_readable(bool readable);
|
||||||
|
|
||||||
|
// Sets the writable state, signaling if necessary.
|
||||||
|
void set_writable(bool writable);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string name_;
|
||||||
|
std::string content_type_;
|
||||||
|
bool readable_;
|
||||||
|
bool writable_;
|
||||||
|
|
||||||
|
DISALLOW_EVIL_CONSTRUCTORS(TransportChannel);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace cricket
|
||||||
|
|
||||||
|
#endif // TALK_P2P_BASE_TRANSPORTCHANNEL_H_
|
||||||
@ -0,0 +1,112 @@
|
|||||||
|
/*
|
||||||
|
* 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/p2p/base/transportchannelproxy.h"
|
||||||
|
#include "talk/base/common.h"
|
||||||
|
#include "talk/p2p/base/transport.h"
|
||||||
|
#include "talk/p2p/base/transportchannelimpl.h"
|
||||||
|
|
||||||
|
namespace cricket {
|
||||||
|
|
||||||
|
TransportChannelProxy::TransportChannelProxy(const std::string& name,
|
||||||
|
const std::string& content_type)
|
||||||
|
: TransportChannel(name, content_type), impl_(NULL) {
|
||||||
|
}
|
||||||
|
|
||||||
|
TransportChannelProxy::~TransportChannelProxy() {
|
||||||
|
if (impl_)
|
||||||
|
impl_->GetTransport()->DestroyChannel(impl_->name());
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransportChannelProxy::SetImplementation(TransportChannelImpl* impl) {
|
||||||
|
impl_ = impl;
|
||||||
|
impl_->SignalReadableState.connect(
|
||||||
|
this, &TransportChannelProxy::OnReadableState);
|
||||||
|
impl_->SignalWritableState.connect(
|
||||||
|
this, &TransportChannelProxy::OnWritableState);
|
||||||
|
impl_->SignalReadPacket.connect(this, &TransportChannelProxy::OnReadPacket);
|
||||||
|
impl_->SignalRouteChange.connect(this, &TransportChannelProxy::OnRouteChange);
|
||||||
|
for (OptionList::iterator it = pending_options_.begin();
|
||||||
|
it != pending_options_.end();
|
||||||
|
++it) {
|
||||||
|
impl_->SetOption(it->first, it->second);
|
||||||
|
}
|
||||||
|
pending_options_.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
int TransportChannelProxy::SendPacket(talk_base::Buffer* packet) {
|
||||||
|
// Fail if we don't have an impl yet.
|
||||||
|
return (impl_) ? impl_->SendPacket(packet) : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int TransportChannelProxy::SendPacket(const char *data, size_t len) {
|
||||||
|
// Fail if we don't have an impl yet.
|
||||||
|
return (impl_) ? impl_->SendPacket(data, len) : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int TransportChannelProxy::SetOption(talk_base::Socket::Option opt, int value) {
|
||||||
|
if (impl_)
|
||||||
|
return impl_->SetOption(opt, value);
|
||||||
|
pending_options_.push_back(OptionPair(opt, value));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int TransportChannelProxy::GetError() {
|
||||||
|
ASSERT(impl_ != NULL); // should not be used until channel is writable
|
||||||
|
return impl_->GetError();
|
||||||
|
}
|
||||||
|
|
||||||
|
P2PTransportChannel* TransportChannelProxy::GetP2PChannel() {
|
||||||
|
if (impl_) {
|
||||||
|
return impl_->GetP2PChannel();
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransportChannelProxy::OnReadableState(TransportChannel* channel) {
|
||||||
|
ASSERT(channel == impl_);
|
||||||
|
set_readable(impl_->readable());
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransportChannelProxy::OnWritableState(TransportChannel* channel) {
|
||||||
|
ASSERT(channel == impl_);
|
||||||
|
set_writable(impl_->writable());
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransportChannelProxy::OnReadPacket(TransportChannel* channel,
|
||||||
|
const char* data, size_t size) {
|
||||||
|
ASSERT(channel == impl_);
|
||||||
|
SignalReadPacket(this, data, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransportChannelProxy::OnRouteChange(TransportChannel* channel,
|
||||||
|
const Candidate& candidate) {
|
||||||
|
ASSERT(channel == impl_);
|
||||||
|
SignalRouteChange(this, candidate);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace cricket
|
||||||
@ -0,0 +1,84 @@
|
|||||||
|
/*
|
||||||
|
* 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 TALK_P2P_BASE_TRANSPORTCHANNELPROXY_H_
|
||||||
|
#define TALK_P2P_BASE_TRANSPORTCHANNELPROXY_H_
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include "talk/p2p/base/transportchannel.h"
|
||||||
|
|
||||||
|
namespace talk_base {
|
||||||
|
class Buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace cricket {
|
||||||
|
|
||||||
|
class TransportChannelImpl;
|
||||||
|
|
||||||
|
// Proxies calls between the client and the transport channel implementation.
|
||||||
|
// This is needed because clients are allowed to create channels before the
|
||||||
|
// network negotiation is complete. Hence, we create a proxy up front, and
|
||||||
|
// when negotiation completes, connect the proxy to the implementaiton.
|
||||||
|
class TransportChannelProxy: public TransportChannel {
|
||||||
|
public:
|
||||||
|
TransportChannelProxy(const std::string& name,
|
||||||
|
const std::string& content_type);
|
||||||
|
virtual ~TransportChannelProxy();
|
||||||
|
|
||||||
|
TransportChannelImpl* impl() { return impl_; }
|
||||||
|
|
||||||
|
// Sets the implementation to which we will proxy.
|
||||||
|
void SetImplementation(TransportChannelImpl* impl);
|
||||||
|
|
||||||
|
// Implementation of the TransportChannel interface. These simply forward to
|
||||||
|
// the implementation.
|
||||||
|
virtual int SendPacket(talk_base::Buffer* packet);
|
||||||
|
virtual int SendPacket(const char *data, size_t len);
|
||||||
|
virtual int SetOption(talk_base::Socket::Option opt, int value);
|
||||||
|
virtual int GetError();
|
||||||
|
virtual P2PTransportChannel* GetP2PChannel();
|
||||||
|
|
||||||
|
private:
|
||||||
|
typedef std::pair<talk_base::Socket::Option, int> OptionPair;
|
||||||
|
typedef std::vector<OptionPair> OptionList;
|
||||||
|
TransportChannelImpl* impl_;
|
||||||
|
OptionList pending_options_;
|
||||||
|
|
||||||
|
// Catch signals from the implementation channel. These just forward to the
|
||||||
|
// client (after updating our state to match).
|
||||||
|
void OnReadableState(TransportChannel* channel);
|
||||||
|
void OnWritableState(TransportChannel* channel);
|
||||||
|
void OnReadPacket(TransportChannel* channel, const char* data, size_t size);
|
||||||
|
void OnRouteChange(TransportChannel* channel, const Candidate& candidate);
|
||||||
|
|
||||||
|
DISALLOW_EVIL_CONSTRUCTORS(TransportChannelProxy);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace cricket
|
||||||
|
|
||||||
|
#endif // TALK_P2P_BASE_TRANSPORTCHANNELPROXY_H_
|
||||||
1259
third_party_mods/libjingle/source/talk/session/phone/channel.cc
Normal file
1259
third_party_mods/libjingle/source/talk/session/phone/channel.cc
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,798 @@
|
|||||||
|
/*
|
||||||
|
* 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 "talk/session/phone/channelmanager.h"
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include "talk/base/common.h"
|
||||||
|
#include "talk/base/logging.h"
|
||||||
|
#include "talk/base/sigslotrepeater.h"
|
||||||
|
#include "talk/base/stringencode.h"
|
||||||
|
#include "talk/session/phone/mediaengine.h"
|
||||||
|
#include "talk/session/phone/soundclip.h"
|
||||||
|
|
||||||
|
namespace cricket {
|
||||||
|
|
||||||
|
enum {
|
||||||
|
MSG_CREATEVOICECHANNEL = 1,
|
||||||
|
MSG_DESTROYVOICECHANNEL = 2,
|
||||||
|
MSG_SETAUDIOOPTIONS = 3,
|
||||||
|
MSG_GETOUTPUTVOLUME = 4,
|
||||||
|
MSG_SETOUTPUTVOLUME = 5,
|
||||||
|
MSG_SETLOCALMONITOR = 6,
|
||||||
|
MSG_SETVOICELOGGING = 7,
|
||||||
|
MSG_CREATEVIDEOCHANNEL = 11,
|
||||||
|
MSG_DESTROYVIDEOCHANNEL = 12,
|
||||||
|
MSG_SETVIDEOOPTIONS = 13,
|
||||||
|
MSG_SETLOCALRENDERER = 14,
|
||||||
|
MSG_SETDEFAULTVIDEOENCODERCONFIG = 15,
|
||||||
|
MSG_SETVIDEOLOGGING = 16,
|
||||||
|
MSG_CREATESOUNDCLIP = 17,
|
||||||
|
MSG_DESTROYSOUNDCLIP = 18,
|
||||||
|
MSG_CAMERASTARTED = 19,
|
||||||
|
MSG_SETVIDEOCAPTURE = 20,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CreationParams : public talk_base::MessageData {
|
||||||
|
CreationParams(BaseSession* session, const std::string& content_name,
|
||||||
|
bool rtcp, VoiceChannel* voice_channel)
|
||||||
|
: session(session),
|
||||||
|
content_name(content_name),
|
||||||
|
rtcp(rtcp),
|
||||||
|
voice_channel(voice_channel),
|
||||||
|
video_channel(NULL) {}
|
||||||
|
BaseSession* session;
|
||||||
|
std::string content_name;
|
||||||
|
bool rtcp;
|
||||||
|
VoiceChannel* voice_channel;
|
||||||
|
VideoChannel* video_channel;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct AudioOptions : public talk_base::MessageData {
|
||||||
|
AudioOptions(int o, const Device* in, const Device* out)
|
||||||
|
: options(o), in_device(in), out_device(out) {}
|
||||||
|
int options;
|
||||||
|
const Device* in_device;
|
||||||
|
const Device* out_device;
|
||||||
|
bool result;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct VolumeLevel : public talk_base::MessageData {
|
||||||
|
VolumeLevel() : level(-1), result(false) {}
|
||||||
|
explicit VolumeLevel(int l) : level(l), result(false) {}
|
||||||
|
int level;
|
||||||
|
bool result;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct VideoOptions : public talk_base::MessageData {
|
||||||
|
explicit VideoOptions(const Device* d) : cam_device(d), result(false) {}
|
||||||
|
const Device* cam_device;
|
||||||
|
bool result;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DefaultVideoEncoderConfig : public talk_base::MessageData {
|
||||||
|
explicit DefaultVideoEncoderConfig(const VideoEncoderConfig& c)
|
||||||
|
: config(c), result(false) {}
|
||||||
|
VideoEncoderConfig config;
|
||||||
|
bool result;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct LocalMonitor : public talk_base::MessageData {
|
||||||
|
explicit LocalMonitor(bool e) : enable(e), result(false) {}
|
||||||
|
bool enable;
|
||||||
|
bool result;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct LocalRenderer : public talk_base::MessageData {
|
||||||
|
explicit LocalRenderer(VideoRenderer* r) : renderer(r), result(false) {}
|
||||||
|
VideoRenderer* renderer;
|
||||||
|
bool result;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct LoggingOptions : public talk_base::MessageData {
|
||||||
|
explicit LoggingOptions(int lev, const char* f) : level(lev), filter(f) {}
|
||||||
|
int level;
|
||||||
|
std::string filter;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CaptureParams : public talk_base::MessageData {
|
||||||
|
explicit CaptureParams(bool c) : capture(c), result(CR_FAILURE) {}
|
||||||
|
|
||||||
|
bool capture;
|
||||||
|
CaptureResult result;
|
||||||
|
};
|
||||||
|
|
||||||
|
ChannelManager::ChannelManager(talk_base::Thread* worker_thread)
|
||||||
|
: media_engine_(MediaEngine::Create()),
|
||||||
|
device_manager_(new DeviceManager()),
|
||||||
|
initialized_(false),
|
||||||
|
main_thread_(talk_base::Thread::Current()),
|
||||||
|
worker_thread_(worker_thread),
|
||||||
|
audio_in_device_(DeviceManager::kDefaultDeviceName),
|
||||||
|
audio_out_device_(DeviceManager::kDefaultDeviceName),
|
||||||
|
audio_options_(MediaEngine::DEFAULT_AUDIO_OPTIONS),
|
||||||
|
local_renderer_(NULL),
|
||||||
|
capturing_(false),
|
||||||
|
monitoring_(false) {
|
||||||
|
Construct();
|
||||||
|
}
|
||||||
|
|
||||||
|
ChannelManager::ChannelManager(MediaEngine* me, DeviceManager* dm,
|
||||||
|
talk_base::Thread* worker_thread)
|
||||||
|
: media_engine_(me),
|
||||||
|
device_manager_(dm),
|
||||||
|
initialized_(false),
|
||||||
|
main_thread_(talk_base::Thread::Current()),
|
||||||
|
worker_thread_(worker_thread),
|
||||||
|
audio_in_device_(DeviceManager::kDefaultDeviceName),
|
||||||
|
audio_out_device_(DeviceManager::kDefaultDeviceName),
|
||||||
|
audio_options_(MediaEngine::DEFAULT_AUDIO_OPTIONS),
|
||||||
|
local_renderer_(NULL),
|
||||||
|
capturing_(false),
|
||||||
|
monitoring_(false) {
|
||||||
|
Construct();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChannelManager::Construct() {
|
||||||
|
// Init the device manager immediately, and set up our default video device.
|
||||||
|
SignalDevicesChange.repeat(device_manager_->SignalDevicesChange);
|
||||||
|
device_manager_->Init();
|
||||||
|
// Set camera_device_ to the name of the default video capturer.
|
||||||
|
SetVideoOptions(DeviceManager::kDefaultDeviceName);
|
||||||
|
|
||||||
|
// Camera is started asynchronously, request callbacks when startup
|
||||||
|
// completes to be able to forward them to the rendering manager.
|
||||||
|
media_engine_->SignalVideoCaptureResult.connect(
|
||||||
|
this, &ChannelManager::OnVideoCaptureResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
ChannelManager::~ChannelManager() {
|
||||||
|
if (initialized_)
|
||||||
|
Terminate();
|
||||||
|
}
|
||||||
|
|
||||||
|
int ChannelManager::GetCapabilities() {
|
||||||
|
return media_engine_->GetCapabilities() & device_manager_->GetCapabilities();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChannelManager::GetSupportedAudioCodecs(
|
||||||
|
std::vector<AudioCodec>* codecs) const {
|
||||||
|
codecs->clear();
|
||||||
|
|
||||||
|
for (std::vector<AudioCodec>::const_iterator it =
|
||||||
|
media_engine_->audio_codecs().begin();
|
||||||
|
it != media_engine_->audio_codecs().end(); ++it) {
|
||||||
|
codecs->push_back(*it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChannelManager::GetSupportedVideoCodecs(
|
||||||
|
std::vector<VideoCodec>* codecs) const {
|
||||||
|
codecs->clear();
|
||||||
|
|
||||||
|
std::vector<VideoCodec>::const_iterator it;
|
||||||
|
for (it = media_engine_->video_codecs().begin();
|
||||||
|
it != media_engine_->video_codecs().end(); ++it) {
|
||||||
|
codecs->push_back(*it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ChannelManager::Init() {
|
||||||
|
ASSERT(!initialized_);
|
||||||
|
if (initialized_) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSERT(worker_thread_ != NULL);
|
||||||
|
if (worker_thread_ && worker_thread_->started()) {
|
||||||
|
if (media_engine_->Init()) {
|
||||||
|
initialized_ = true;
|
||||||
|
// Now that we're initialized, apply any stored preferences. A preferred
|
||||||
|
// device might have been unplugged. In this case, we fallback to the
|
||||||
|
// default device but keep the user preferences. The preferences are
|
||||||
|
// changed only when the Javascript FE changes them.
|
||||||
|
const std::string preferred_audio_in_device = audio_in_device_;
|
||||||
|
const std::string preferred_audio_out_device = audio_out_device_;
|
||||||
|
const std::string preferred_camera_device = camera_device_;
|
||||||
|
Device device;
|
||||||
|
if (!device_manager_->GetAudioInputDevice(audio_in_device_, &device)) {
|
||||||
|
LOG(LS_WARNING) << "The preferred microphone '" << audio_in_device_
|
||||||
|
<< "' is unavailable. Fall back to the default.";
|
||||||
|
audio_in_device_ = DeviceManager::kDefaultDeviceName;
|
||||||
|
}
|
||||||
|
if (!device_manager_->GetAudioOutputDevice(audio_out_device_, &device)) {
|
||||||
|
LOG(LS_WARNING) << "The preferred speaker '" << audio_out_device_
|
||||||
|
<< "' is unavailable. Fall back to the default.";
|
||||||
|
audio_out_device_ = DeviceManager::kDefaultDeviceName;
|
||||||
|
}
|
||||||
|
if (!device_manager_->GetVideoCaptureDevice(camera_device_, &device)) {
|
||||||
|
if (!camera_device_.empty()) {
|
||||||
|
LOG(LS_WARNING) << "The preferred camera '" << camera_device_
|
||||||
|
<< "' is unavailable. Fall back to the default.";
|
||||||
|
}
|
||||||
|
camera_device_ = DeviceManager::kDefaultDeviceName;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!SetAudioOptions(audio_in_device_, audio_out_device_,
|
||||||
|
audio_options_)) {
|
||||||
|
LOG(LS_WARNING) << "Failed to SetAudioOptions with"
|
||||||
|
<< " microphone: " << audio_in_device_
|
||||||
|
<< " speaker: " << audio_out_device_
|
||||||
|
<< " options: " << audio_options_;
|
||||||
|
}
|
||||||
|
if (!SetVideoOptions(camera_device_) && !camera_device_.empty()) {
|
||||||
|
LOG(LS_WARNING) << "Failed to SetVideoOptions with camera: "
|
||||||
|
<< camera_device_;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restore the user preferences.
|
||||||
|
audio_in_device_ = preferred_audio_in_device;
|
||||||
|
audio_out_device_ = preferred_audio_out_device;
|
||||||
|
camera_device_ = preferred_camera_device;
|
||||||
|
|
||||||
|
// Now apply the default video codec that has been set earlier.
|
||||||
|
if (default_video_encoder_config_.max_codec.id != 0) {
|
||||||
|
SetDefaultVideoEncoderConfig(default_video_encoder_config_);
|
||||||
|
}
|
||||||
|
// And the local renderer.
|
||||||
|
if (local_renderer_) {
|
||||||
|
SetLocalRenderer(local_renderer_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return initialized_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChannelManager::Terminate() {
|
||||||
|
ASSERT(initialized_);
|
||||||
|
if (!initialized_) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Need to destroy the voice/video channels
|
||||||
|
while (!video_channels_.empty()) {
|
||||||
|
DestroyVideoChannel_w(video_channels_.back());
|
||||||
|
}
|
||||||
|
while (!voice_channels_.empty()) {
|
||||||
|
DestroyVoiceChannel_w(voice_channels_.back());
|
||||||
|
}
|
||||||
|
while (!soundclips_.empty()) {
|
||||||
|
DestroySoundclip_w(soundclips_.back());
|
||||||
|
}
|
||||||
|
|
||||||
|
media_engine_->Terminate();
|
||||||
|
initialized_ = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
VoiceChannel* ChannelManager::CreateVoiceChannel(
|
||||||
|
BaseSession* session, const std::string& content_name, bool rtcp) {
|
||||||
|
CreationParams params(session, content_name, rtcp, NULL);
|
||||||
|
return (Send(MSG_CREATEVOICECHANNEL, ¶ms)) ? params.voice_channel : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
VoiceChannel* ChannelManager::CreateVoiceChannel_w(
|
||||||
|
BaseSession* session, const std::string& content_name, bool rtcp) {
|
||||||
|
talk_base::CritScope cs(&crit_);
|
||||||
|
|
||||||
|
// This is ok to alloc from a thread other than the worker thread
|
||||||
|
ASSERT(initialized_);
|
||||||
|
VoiceMediaChannel* media_channel = media_engine_->CreateChannel();
|
||||||
|
if (media_channel == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
VoiceChannel* voice_channel = new VoiceChannel(
|
||||||
|
worker_thread_, media_engine_.get(), media_channel,
|
||||||
|
session, content_name, rtcp);
|
||||||
|
voice_channels_.push_back(voice_channel);
|
||||||
|
return voice_channel;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChannelManager::DestroyVoiceChannel(VoiceChannel* voice_channel) {
|
||||||
|
if (voice_channel) {
|
||||||
|
talk_base::TypedMessageData<VoiceChannel *> data(voice_channel);
|
||||||
|
Send(MSG_DESTROYVOICECHANNEL, &data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChannelManager::DestroyVoiceChannel_w(VoiceChannel* voice_channel) {
|
||||||
|
talk_base::CritScope cs(&crit_);
|
||||||
|
// Destroy voice channel.
|
||||||
|
ASSERT(initialized_);
|
||||||
|
VoiceChannels::iterator it = std::find(voice_channels_.begin(),
|
||||||
|
voice_channels_.end(), voice_channel);
|
||||||
|
ASSERT(it != voice_channels_.end());
|
||||||
|
if (it == voice_channels_.end())
|
||||||
|
return;
|
||||||
|
|
||||||
|
voice_channels_.erase(it);
|
||||||
|
delete voice_channel;
|
||||||
|
}
|
||||||
|
|
||||||
|
VideoChannel* ChannelManager::CreateVideoChannel(
|
||||||
|
BaseSession* session, const std::string& content_name, bool rtcp,
|
||||||
|
VoiceChannel* voice_channel) {
|
||||||
|
CreationParams params(session, content_name, rtcp, voice_channel);
|
||||||
|
return (Send(MSG_CREATEVIDEOCHANNEL, ¶ms)) ? params.video_channel : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
VideoChannel* ChannelManager::CreateVideoChannel_w(
|
||||||
|
BaseSession* session, const std::string& content_name, bool rtcp,
|
||||||
|
VoiceChannel* voice_channel) {
|
||||||
|
talk_base::CritScope cs(&crit_);
|
||||||
|
|
||||||
|
// This is ok to alloc from a thread other than the worker thread
|
||||||
|
ASSERT(initialized_);
|
||||||
|
VideoMediaChannel* media_channel =
|
||||||
|
// voice_channel can be NULL in case of NullVoiceEngine.
|
||||||
|
media_engine_->CreateVideoChannel(voice_channel ?
|
||||||
|
voice_channel->media_channel() : NULL);
|
||||||
|
if (media_channel == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
VideoChannel* video_channel = new VideoChannel(
|
||||||
|
worker_thread_, media_engine_.get(), media_channel,
|
||||||
|
session, content_name, rtcp, voice_channel);
|
||||||
|
video_channels_.push_back(video_channel);
|
||||||
|
return video_channel;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChannelManager::DestroyVideoChannel(VideoChannel* video_channel) {
|
||||||
|
if (video_channel) {
|
||||||
|
talk_base::TypedMessageData<VideoChannel *> data(video_channel);
|
||||||
|
Send(MSG_DESTROYVIDEOCHANNEL, &data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChannelManager::DestroyVideoChannel_w(VideoChannel *video_channel) {
|
||||||
|
talk_base::CritScope cs(&crit_);
|
||||||
|
// Destroy voice channel.
|
||||||
|
ASSERT(initialized_);
|
||||||
|
VideoChannels::iterator it = std::find(video_channels_.begin(),
|
||||||
|
video_channels_.end(), video_channel);
|
||||||
|
if (it == video_channels_.end())
|
||||||
|
return;
|
||||||
|
|
||||||
|
video_channels_.erase(it);
|
||||||
|
delete video_channel;
|
||||||
|
}
|
||||||
|
|
||||||
|
Soundclip* ChannelManager::CreateSoundclip() {
|
||||||
|
talk_base::TypedMessageData<Soundclip*> data(NULL);
|
||||||
|
Send(MSG_CREATESOUNDCLIP, &data);
|
||||||
|
return data.data();
|
||||||
|
}
|
||||||
|
|
||||||
|
Soundclip* ChannelManager::CreateSoundclip_w() {
|
||||||
|
talk_base::CritScope cs(&crit_);
|
||||||
|
|
||||||
|
ASSERT(initialized_);
|
||||||
|
ASSERT(worker_thread_ == talk_base::Thread::Current());
|
||||||
|
|
||||||
|
SoundclipMedia* soundclip_media = media_engine_->CreateSoundclip();
|
||||||
|
if (!soundclip_media) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
Soundclip* soundclip = new Soundclip(worker_thread_, soundclip_media);
|
||||||
|
soundclips_.push_back(soundclip);
|
||||||
|
return soundclip;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChannelManager::DestroySoundclip(Soundclip* soundclip) {
|
||||||
|
if (soundclip) {
|
||||||
|
talk_base::TypedMessageData<Soundclip*> data(soundclip);
|
||||||
|
Send(MSG_DESTROYSOUNDCLIP, &data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChannelManager::DestroySoundclip_w(Soundclip* soundclip) {
|
||||||
|
talk_base::CritScope cs(&crit_);
|
||||||
|
// Destroy soundclip.
|
||||||
|
ASSERT(initialized_);
|
||||||
|
Soundclips::iterator it = std::find(soundclips_.begin(),
|
||||||
|
soundclips_.end(), soundclip);
|
||||||
|
ASSERT(it != soundclips_.end());
|
||||||
|
if (it == soundclips_.end())
|
||||||
|
return;
|
||||||
|
|
||||||
|
soundclips_.erase(it);
|
||||||
|
delete soundclip;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ChannelManager::GetAudioOptions(std::string* in_name,
|
||||||
|
std::string* out_name, int* opts) {
|
||||||
|
*in_name = audio_in_device_;
|
||||||
|
*out_name = audio_out_device_;
|
||||||
|
*opts = audio_options_;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ChannelManager::SetAudioOptions(const std::string& in_name,
|
||||||
|
const std::string& out_name, int opts) {
|
||||||
|
// Get device ids from DeviceManager.
|
||||||
|
Device in_dev, out_dev;
|
||||||
|
if (!device_manager_->GetAudioInputDevice(in_name, &in_dev)) {
|
||||||
|
LOG(LS_WARNING) << "Failed to GetAudioInputDevice: " << in_name;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!device_manager_->GetAudioOutputDevice(out_name, &out_dev)) {
|
||||||
|
LOG(LS_WARNING) << "Failed to GetAudioOutputDevice: " << out_name;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we're initialized, pass the settings to the media engine.
|
||||||
|
bool ret = true;
|
||||||
|
if (initialized_) {
|
||||||
|
AudioOptions options(opts, &in_dev, &out_dev);
|
||||||
|
ret = (Send(MSG_SETAUDIOOPTIONS, &options) && options.result);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If all worked well, save the values for use in GetAudioOptions.
|
||||||
|
if (ret) {
|
||||||
|
audio_options_ = opts;
|
||||||
|
audio_in_device_ = in_name;
|
||||||
|
audio_out_device_ = out_name;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ChannelManager::SetAudioOptions_w(int opts, const Device* in_dev,
|
||||||
|
const Device* out_dev) {
|
||||||
|
ASSERT(worker_thread_ == talk_base::Thread::Current());
|
||||||
|
ASSERT(initialized_);
|
||||||
|
|
||||||
|
// Set audio options
|
||||||
|
bool ret = media_engine_->SetAudioOptions(opts);
|
||||||
|
|
||||||
|
// Set the audio devices
|
||||||
|
if (ret) {
|
||||||
|
talk_base::CritScope cs(&crit_);
|
||||||
|
ret = media_engine_->SetSoundDevices(in_dev, out_dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ChannelManager::GetOutputVolume(int* level) {
|
||||||
|
VolumeLevel volume;
|
||||||
|
if (!Send(MSG_GETOUTPUTVOLUME, &volume) || !volume.result) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
*level = volume.level;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ChannelManager::GetOutputVolume_w(int* level) {
|
||||||
|
ASSERT(worker_thread_ == talk_base::Thread::Current());
|
||||||
|
ASSERT(initialized_);
|
||||||
|
return media_engine_->GetOutputVolume(level);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ChannelManager::SetOutputVolume(int level) {
|
||||||
|
VolumeLevel volume(level);
|
||||||
|
return (Send(MSG_SETOUTPUTVOLUME, &volume) && volume.result);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ChannelManager::SetOutputVolume_w(int level) {
|
||||||
|
ASSERT(worker_thread_ == talk_base::Thread::Current());
|
||||||
|
ASSERT(initialized_);
|
||||||
|
return media_engine_->SetOutputVolume(level);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ChannelManager::GetVideoOptions(std::string* cam_name) {
|
||||||
|
*cam_name = camera_device_;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ChannelManager::SetVideoOptions(const std::string& cam_name) {
|
||||||
|
Device device;
|
||||||
|
if (!device_manager_->GetVideoCaptureDevice(cam_name, &device)) {
|
||||||
|
if (!cam_name.empty()) {
|
||||||
|
LOG(LS_WARNING) << "Device manager can't find camera: " << cam_name;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we're running, tell the media engine about it.
|
||||||
|
bool ret = true;
|
||||||
|
if (initialized_) {
|
||||||
|
VideoOptions options(&device);
|
||||||
|
ret = (Send(MSG_SETVIDEOOPTIONS, &options) && options.result);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If everything worked, retain the name of the selected camera.
|
||||||
|
if (ret) {
|
||||||
|
camera_device_ = device.name;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ChannelManager::SetVideoOptions_w(const Device* cam_device) {
|
||||||
|
ASSERT(worker_thread_ == talk_base::Thread::Current());
|
||||||
|
ASSERT(initialized_);
|
||||||
|
|
||||||
|
// Set the video input device
|
||||||
|
return media_engine_->SetVideoCaptureDevice(cam_device);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ChannelManager::SetDefaultVideoEncoderConfig(const VideoEncoderConfig& c) {
|
||||||
|
bool ret = true;
|
||||||
|
if (initialized_) {
|
||||||
|
DefaultVideoEncoderConfig config(c);
|
||||||
|
ret = Send(MSG_SETDEFAULTVIDEOENCODERCONFIG, &config) && config.result;
|
||||||
|
}
|
||||||
|
if (ret) {
|
||||||
|
default_video_encoder_config_ = c;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ChannelManager::SetDefaultVideoEncoderConfig_w(
|
||||||
|
const VideoEncoderConfig& c) {
|
||||||
|
ASSERT(worker_thread_ == talk_base::Thread::Current());
|
||||||
|
ASSERT(initialized_);
|
||||||
|
return media_engine_->SetDefaultVideoEncoderConfig(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ChannelManager::SetLocalMonitor(bool enable) {
|
||||||
|
LocalMonitor monitor(enable);
|
||||||
|
bool ret = Send(MSG_SETLOCALMONITOR, &monitor) && monitor.result;
|
||||||
|
if (ret) {
|
||||||
|
monitoring_ = enable;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ChannelManager::SetLocalMonitor_w(bool enable) {
|
||||||
|
ASSERT(worker_thread_ == talk_base::Thread::Current());
|
||||||
|
ASSERT(initialized_);
|
||||||
|
return media_engine_->SetLocalMonitor(enable);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ChannelManager::SetLocalRenderer(VideoRenderer* renderer) {
|
||||||
|
bool ret = true;
|
||||||
|
if (initialized_) {
|
||||||
|
LocalRenderer local(renderer);
|
||||||
|
ret = (Send(MSG_SETLOCALRENDERER, &local) && local.result);
|
||||||
|
}
|
||||||
|
if (ret) {
|
||||||
|
local_renderer_ = renderer;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ChannelManager::SetLocalRenderer_w(VideoRenderer* renderer) {
|
||||||
|
ASSERT(worker_thread_ == talk_base::Thread::Current());
|
||||||
|
ASSERT(initialized_);
|
||||||
|
return media_engine_->SetLocalRenderer(renderer);
|
||||||
|
}
|
||||||
|
|
||||||
|
CaptureResult ChannelManager::SetVideoCapture(bool capture) {
|
||||||
|
bool ret;
|
||||||
|
CaptureParams capture_params(capture);
|
||||||
|
ret = (Send(MSG_SETVIDEOCAPTURE, &capture_params) &&
|
||||||
|
(capture_params.result != CR_FAILURE));
|
||||||
|
if (ret) {
|
||||||
|
capturing_ = capture;
|
||||||
|
}
|
||||||
|
return capture_params.result;
|
||||||
|
}
|
||||||
|
|
||||||
|
CaptureResult ChannelManager::SetVideoCapture_w(bool capture) {
|
||||||
|
ASSERT(worker_thread_ == talk_base::Thread::Current());
|
||||||
|
ASSERT(initialized_);
|
||||||
|
return media_engine_->SetVideoCapture(capture);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChannelManager::SetVoiceLogging(int level, const char* filter) {
|
||||||
|
SetMediaLogging(false, level, filter);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChannelManager::SetVideoLogging(int level, const char* filter) {
|
||||||
|
SetMediaLogging(true, level, filter);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChannelManager::SetMediaLogging(bool video, int level,
|
||||||
|
const char* filter) {
|
||||||
|
// Can be called before initialization; in this case, the worker function
|
||||||
|
// is simply called on the main thread.
|
||||||
|
if (initialized_) {
|
||||||
|
LoggingOptions options(level, filter);
|
||||||
|
Send((video) ? MSG_SETVIDEOLOGGING : MSG_SETVOICELOGGING, &options);
|
||||||
|
} else {
|
||||||
|
SetMediaLogging_w(video, level, filter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChannelManager::SetMediaLogging_w(bool video, int level,
|
||||||
|
const char* filter) {
|
||||||
|
// Can be called before initialization
|
||||||
|
ASSERT(worker_thread_ == talk_base::Thread::Current() || !initialized_);
|
||||||
|
if (video) {
|
||||||
|
media_engine_->SetVideoLogging(level, filter);
|
||||||
|
} else {
|
||||||
|
media_engine_->SetVoiceLogging(level, filter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ChannelManager::Send(uint32 id, talk_base::MessageData* data) {
|
||||||
|
if (!worker_thread_ || !initialized_) return false;
|
||||||
|
worker_thread_->Send(this, id, data);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChannelManager::OnVideoCaptureResult(CaptureResult result) {
|
||||||
|
capturing_ = result == CR_SUCCESS;
|
||||||
|
main_thread_->Post(this, MSG_CAMERASTARTED,
|
||||||
|
new talk_base::TypedMessageData<CaptureResult>(result));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChannelManager::OnMessage(talk_base::Message* message) {
|
||||||
|
talk_base::MessageData* data = message->pdata;
|
||||||
|
switch (message->message_id) {
|
||||||
|
case MSG_CREATEVOICECHANNEL: {
|
||||||
|
CreationParams* p = static_cast<CreationParams*>(data);
|
||||||
|
p->voice_channel =
|
||||||
|
CreateVoiceChannel_w(p->session, p->content_name, p->rtcp);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MSG_DESTROYVOICECHANNEL: {
|
||||||
|
VoiceChannel* p = static_cast<talk_base::TypedMessageData<VoiceChannel*>*>
|
||||||
|
(data)->data();
|
||||||
|
DestroyVoiceChannel_w(p);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MSG_CREATEVIDEOCHANNEL: {
|
||||||
|
CreationParams* p = static_cast<CreationParams*>(data);
|
||||||
|
p->video_channel = CreateVideoChannel_w(p->session, p->content_name,
|
||||||
|
p->rtcp, p->voice_channel);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MSG_DESTROYVIDEOCHANNEL: {
|
||||||
|
VideoChannel* p = static_cast<talk_base::TypedMessageData<VideoChannel*>*>
|
||||||
|
(data)->data();
|
||||||
|
DestroyVideoChannel_w(p);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MSG_CREATESOUNDCLIP: {
|
||||||
|
talk_base::TypedMessageData<Soundclip*> *p =
|
||||||
|
static_cast<talk_base::TypedMessageData<Soundclip*>*>(data);
|
||||||
|
p->data() = CreateSoundclip_w();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MSG_DESTROYSOUNDCLIP: {
|
||||||
|
talk_base::TypedMessageData<Soundclip*> *p =
|
||||||
|
static_cast<talk_base::TypedMessageData<Soundclip*>*>(data);
|
||||||
|
DestroySoundclip_w(p->data());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MSG_SETAUDIOOPTIONS: {
|
||||||
|
AudioOptions* p = static_cast<AudioOptions*>(data);
|
||||||
|
p->result = SetAudioOptions_w(p->options,
|
||||||
|
p->in_device, p->out_device);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MSG_GETOUTPUTVOLUME: {
|
||||||
|
VolumeLevel* p = static_cast<VolumeLevel*>(data);
|
||||||
|
p->result = GetOutputVolume_w(&p->level);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MSG_SETOUTPUTVOLUME: {
|
||||||
|
VolumeLevel* p = static_cast<VolumeLevel*>(data);
|
||||||
|
p->result = SetOutputVolume_w(p->level);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MSG_SETLOCALMONITOR: {
|
||||||
|
LocalMonitor* p = static_cast<LocalMonitor*>(data);
|
||||||
|
p->result = SetLocalMonitor_w(p->enable);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MSG_SETVIDEOOPTIONS: {
|
||||||
|
VideoOptions* p = static_cast<VideoOptions*>(data);
|
||||||
|
p->result = SetVideoOptions_w(p->cam_device);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MSG_SETDEFAULTVIDEOENCODERCONFIG: {
|
||||||
|
DefaultVideoEncoderConfig* p =
|
||||||
|
static_cast<DefaultVideoEncoderConfig*>(data);
|
||||||
|
p->result = SetDefaultVideoEncoderConfig_w(p->config);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MSG_SETLOCALRENDERER: {
|
||||||
|
LocalRenderer* p = static_cast<LocalRenderer*>(data);
|
||||||
|
p->result = SetLocalRenderer_w(p->renderer);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MSG_SETVIDEOCAPTURE: {
|
||||||
|
CaptureParams* p = static_cast<CaptureParams*>(data);
|
||||||
|
p->result = SetVideoCapture_w(p->capture);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MSG_SETVOICELOGGING:
|
||||||
|
case MSG_SETVIDEOLOGGING: {
|
||||||
|
LoggingOptions* p = static_cast<LoggingOptions*>(data);
|
||||||
|
bool video = (message->message_id == MSG_SETVIDEOLOGGING);
|
||||||
|
SetMediaLogging_w(video, p->level, p->filter.c_str());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MSG_CAMERASTARTED: {
|
||||||
|
talk_base::TypedMessageData<CaptureResult>* data =
|
||||||
|
static_cast<talk_base::TypedMessageData<CaptureResult>*>(
|
||||||
|
message->pdata);
|
||||||
|
SignalVideoCaptureResult(data->data());
|
||||||
|
delete data;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void GetDeviceNames(const std::vector<Device>& devs,
|
||||||
|
std::vector<std::string>* names) {
|
||||||
|
names->clear();
|
||||||
|
for (size_t i = 0; i < devs.size(); ++i) {
|
||||||
|
names->push_back(devs[i].name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ChannelManager::GetAudioInputDevices(std::vector<std::string>* names) {
|
||||||
|
names->clear();
|
||||||
|
std::vector<Device> devs;
|
||||||
|
bool ret = device_manager_->GetAudioInputDevices(&devs);
|
||||||
|
if (ret)
|
||||||
|
GetDeviceNames(devs, names);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ChannelManager::GetAudioOutputDevices(std::vector<std::string>* names) {
|
||||||
|
names->clear();
|
||||||
|
std::vector<Device> devs;
|
||||||
|
bool ret = device_manager_->GetAudioOutputDevices(&devs);
|
||||||
|
if (ret)
|
||||||
|
GetDeviceNames(devs, names);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ChannelManager::GetVideoCaptureDevices(std::vector<std::string>* names) {
|
||||||
|
names->clear();
|
||||||
|
std::vector<Device> devs;
|
||||||
|
bool ret = device_manager_->GetVideoCaptureDevices(&devs);
|
||||||
|
if (ret)
|
||||||
|
GetDeviceNames(devs, names);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace cricket
|
||||||
@ -0,0 +1,208 @@
|
|||||||
|
/*
|
||||||
|
* 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 TALK_SESSION_PHONE_CHANNELMANAGER_H_
|
||||||
|
#define TALK_SESSION_PHONE_CHANNELMANAGER_H_
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "talk/base/criticalsection.h"
|
||||||
|
#include "talk/base/sigslotrepeater.h"
|
||||||
|
#include "talk/base/thread.h"
|
||||||
|
#include "talk/p2p/base/session.h"
|
||||||
|
#include "talk/session/phone/voicechannel.h"
|
||||||
|
#include "talk/session/phone/mediaengine.h"
|
||||||
|
#include "talk/session/phone/devicemanager.h"
|
||||||
|
|
||||||
|
namespace cricket {
|
||||||
|
|
||||||
|
class Soundclip;
|
||||||
|
class VoiceChannel;
|
||||||
|
|
||||||
|
// ChannelManager allows the MediaEngine to run on a separate thread, and takes
|
||||||
|
// care of marshalling calls between threads. It also creates and keeps track of
|
||||||
|
// voice and video channels; by doing so, it can temporarily pause all the
|
||||||
|
// channels when a new audio or video device is chosen. The voice and video
|
||||||
|
// channels are stored in separate vectors, to easily allow operations on just
|
||||||
|
// voice or just video channels.
|
||||||
|
// ChannelManager also allows the application to discover what devices it has
|
||||||
|
// using device manager.
|
||||||
|
class ChannelManager : public talk_base::MessageHandler,
|
||||||
|
public sigslot::has_slots<> {
|
||||||
|
public:
|
||||||
|
// Creates the channel manager, and specifies the worker thread to use.
|
||||||
|
explicit ChannelManager(talk_base::Thread* worker);
|
||||||
|
// For testing purposes. Allows the media engine and dev manager to be mocks.
|
||||||
|
// The ChannelManager takes ownership of these objects.
|
||||||
|
ChannelManager(MediaEngine* me, DeviceManager* dm, talk_base::Thread* worker);
|
||||||
|
~ChannelManager();
|
||||||
|
|
||||||
|
// Accessors for the worker thread, allowing it to be set after construction,
|
||||||
|
// but before Init. set_worker_thread will return false if called after Init.
|
||||||
|
talk_base::Thread* worker_thread() const { return worker_thread_; }
|
||||||
|
bool set_worker_thread(talk_base::Thread* thread) {
|
||||||
|
if (initialized_) return false;
|
||||||
|
worker_thread_ = thread;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gets capabilities. Can be called prior to starting the media engine.
|
||||||
|
int GetCapabilities();
|
||||||
|
|
||||||
|
// Retrieves the list of supported audio & video codec types.
|
||||||
|
// Can be called before starting the media engine.
|
||||||
|
void GetSupportedAudioCodecs(std::vector<AudioCodec>* codecs) const;
|
||||||
|
void GetSupportedVideoCodecs(std::vector<VideoCodec>* codecs) const;
|
||||||
|
|
||||||
|
// Indicates whether the media engine is started.
|
||||||
|
bool initialized() const { return initialized_; }
|
||||||
|
// Starts up the media engine.
|
||||||
|
bool Init();
|
||||||
|
// TODO: Remove this temporary API once Flute is updated.
|
||||||
|
bool Init(talk_base::Thread* thread) {
|
||||||
|
return set_worker_thread(thread) && Init();
|
||||||
|
}
|
||||||
|
// Shuts down the media engine.
|
||||||
|
void Terminate();
|
||||||
|
|
||||||
|
// The operations below all occur on the worker thread.
|
||||||
|
|
||||||
|
// Creates a voice channel, to be associated with the specified session.
|
||||||
|
VoiceChannel* CreateVoiceChannel(
|
||||||
|
BaseSession* session, const std::string& content_name, bool rtcp);
|
||||||
|
// Destroys a voice channel created with the Create API.
|
||||||
|
void DestroyVoiceChannel(VoiceChannel* voice_channel);
|
||||||
|
// Creates a video channel, synced with the specified voice channel, and
|
||||||
|
// associated with the specified session.
|
||||||
|
VideoChannel* CreateVideoChannel(
|
||||||
|
BaseSession* session, const std::string& content_name, bool rtcp,
|
||||||
|
VoiceChannel* voice_channel);
|
||||||
|
// Destroys a video channel created with the Create API.
|
||||||
|
void DestroyVideoChannel(VideoChannel* video_channel);
|
||||||
|
|
||||||
|
// Creates a soundclip.
|
||||||
|
Soundclip* CreateSoundclip();
|
||||||
|
// Destroys a soundclip created with the Create API.
|
||||||
|
void DestroySoundclip(Soundclip* soundclip);
|
||||||
|
|
||||||
|
// Indicates whether any channels exist.
|
||||||
|
bool has_channels() const {
|
||||||
|
return (!voice_channels_.empty() || !video_channels_.empty() ||
|
||||||
|
!soundclips_.empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configures the audio and video devices.
|
||||||
|
bool GetAudioOptions(std::string* wave_in_device,
|
||||||
|
std::string* wave_out_device, int* opts);
|
||||||
|
bool SetAudioOptions(const std::string& wave_in_device,
|
||||||
|
const std::string& wave_out_device, int opts);
|
||||||
|
bool GetOutputVolume(int* level);
|
||||||
|
bool SetOutputVolume(int level);
|
||||||
|
bool GetVideoOptions(std::string* cam_device);
|
||||||
|
bool SetVideoOptions(const std::string& cam_device);
|
||||||
|
bool SetDefaultVideoEncoderConfig(const VideoEncoderConfig& config);
|
||||||
|
|
||||||
|
// Starts/stops the local microphone and enables polling of the input level.
|
||||||
|
bool SetLocalMonitor(bool enable);
|
||||||
|
bool monitoring() const { return monitoring_; }
|
||||||
|
// Sets the local renderer where to renderer the local camera.
|
||||||
|
bool SetLocalRenderer(VideoRenderer* renderer);
|
||||||
|
// Starts and stops the local camera and renders it to the local renderer.
|
||||||
|
CaptureResult SetVideoCapture(bool capture);
|
||||||
|
bool capturing() const { return capturing_; }
|
||||||
|
|
||||||
|
// Configures the logging output of the mediaengine(s).
|
||||||
|
void SetVoiceLogging(int level, const char* filter);
|
||||||
|
void SetVideoLogging(int level, const char* filter);
|
||||||
|
|
||||||
|
// The operations below occur on the main thread.
|
||||||
|
|
||||||
|
bool GetAudioInputDevices(std::vector<std::string>* names);
|
||||||
|
bool GetAudioOutputDevices(std::vector<std::string>* names);
|
||||||
|
bool GetVideoCaptureDevices(std::vector<std::string>* names);
|
||||||
|
sigslot::repeater0<> SignalDevicesChange;
|
||||||
|
sigslot::signal1<CaptureResult> SignalVideoCaptureResult;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool Send(uint32 id, talk_base::MessageData* pdata);
|
||||||
|
void OnMessage(talk_base::Message *message);
|
||||||
|
MediaEngine* media_engine() { return media_engine_.get(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
typedef std::vector<VoiceChannel*> VoiceChannels;
|
||||||
|
typedef std::vector<VideoChannel*> VideoChannels;
|
||||||
|
typedef std::vector<Soundclip*> Soundclips;
|
||||||
|
|
||||||
|
void Construct();
|
||||||
|
VoiceChannel* CreateVoiceChannel_w(
|
||||||
|
BaseSession* session, const std::string& content_name, bool rtcp);
|
||||||
|
void DestroyVoiceChannel_w(VoiceChannel* voice_channel);
|
||||||
|
VideoChannel* CreateVideoChannel_w(
|
||||||
|
BaseSession* session, const std::string& content_name, bool rtcp,
|
||||||
|
VoiceChannel* voice_channel);
|
||||||
|
void DestroyVideoChannel_w(VideoChannel* video_channel);
|
||||||
|
Soundclip* CreateSoundclip_w();
|
||||||
|
void DestroySoundclip_w(Soundclip* soundclip);
|
||||||
|
bool SetAudioOptions_w(int opts, const Device* in_dev,
|
||||||
|
const Device* out_dev);
|
||||||
|
bool GetOutputVolume_w(int* level);
|
||||||
|
bool SetOutputVolume_w(int level);
|
||||||
|
bool SetLocalMonitor_w(bool enable);
|
||||||
|
bool SetVideoOptions_w(const Device* cam_device);
|
||||||
|
bool SetDefaultVideoEncoderConfig_w(const VideoEncoderConfig& config);
|
||||||
|
bool SetLocalRenderer_w(VideoRenderer* renderer);
|
||||||
|
CaptureResult SetVideoCapture_w(bool capture);
|
||||||
|
void SetMediaLogging(bool video, int level, const char* filter);
|
||||||
|
void SetMediaLogging_w(bool video, int level, const char* filter);
|
||||||
|
void OnVideoCaptureResult(CaptureResult result);
|
||||||
|
|
||||||
|
talk_base::CriticalSection crit_;
|
||||||
|
talk_base::scoped_ptr<MediaEngine> media_engine_;
|
||||||
|
talk_base::scoped_ptr<DeviceManager> device_manager_;
|
||||||
|
bool initialized_;
|
||||||
|
talk_base::Thread* main_thread_;
|
||||||
|
talk_base::Thread* worker_thread_;
|
||||||
|
|
||||||
|
VoiceChannels voice_channels_;
|
||||||
|
VideoChannels video_channels_;
|
||||||
|
Soundclips soundclips_;
|
||||||
|
|
||||||
|
std::string audio_in_device_;
|
||||||
|
std::string audio_out_device_;
|
||||||
|
int audio_options_;
|
||||||
|
std::string camera_device_;
|
||||||
|
VideoEncoderConfig default_video_encoder_config_;
|
||||||
|
VideoRenderer* local_renderer_;
|
||||||
|
|
||||||
|
bool capturing_;
|
||||||
|
bool monitoring_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace cricket
|
||||||
|
|
||||||
|
#endif // TALK_SESSION_PHONE_CHANNELMANAGER_H_
|
||||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,110 @@
|
|||||||
|
/*
|
||||||
|
* 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 TALK_SESSION_PHONE_DEVICEMANAGER_H_
|
||||||
|
#define TALK_SESSION_PHONE_DEVICEMANAGER_H_
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "talk/base/sigslot.h"
|
||||||
|
#include "talk/base/stringencode.h"
|
||||||
|
#ifdef LINUX_SOUND_USED
|
||||||
|
#include "talk/sound/soundsystemfactory.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace cricket {
|
||||||
|
|
||||||
|
class DeviceWatcher;
|
||||||
|
|
||||||
|
// Used to represent an audio or video capture or render device.
|
||||||
|
class Device {
|
||||||
|
public:
|
||||||
|
Device() {}
|
||||||
|
Device(const std::string& first, int second)
|
||||||
|
: name(first),
|
||||||
|
id(talk_base::ToString(second)) {
|
||||||
|
}
|
||||||
|
Device(const std::string& first, const std::string& second)
|
||||||
|
: name(first), id(second) {}
|
||||||
|
|
||||||
|
std::string name;
|
||||||
|
std::string id;
|
||||||
|
};
|
||||||
|
|
||||||
|
// DeviceManager manages the audio and video devices on the system.
|
||||||
|
// Methods are virtual to allow for easy stubbing/mocking in tests.
|
||||||
|
class DeviceManager {
|
||||||
|
public:
|
||||||
|
DeviceManager();
|
||||||
|
virtual ~DeviceManager();
|
||||||
|
|
||||||
|
// Initialization
|
||||||
|
virtual bool Init();
|
||||||
|
virtual void Terminate();
|
||||||
|
bool initialized() const { return initialized_; }
|
||||||
|
|
||||||
|
// Capabilities
|
||||||
|
virtual int GetCapabilities();
|
||||||
|
|
||||||
|
// Device enumeration
|
||||||
|
virtual bool GetAudioInputDevices(std::vector<Device>* devices);
|
||||||
|
virtual bool GetAudioOutputDevices(std::vector<Device>* devices);
|
||||||
|
|
||||||
|
bool GetAudioInputDevice(const std::string& name, Device* out);
|
||||||
|
bool GetAudioOutputDevice(const std::string& name, Device* out);
|
||||||
|
|
||||||
|
virtual bool GetVideoCaptureDevices(std::vector<Device>* devs);
|
||||||
|
bool GetVideoCaptureDevice(const std::string& name, Device* out);
|
||||||
|
|
||||||
|
sigslot::signal0<> SignalDevicesChange;
|
||||||
|
|
||||||
|
void OnDevicesChange() { SignalDevicesChange(); }
|
||||||
|
|
||||||
|
static const std::string kDefaultDeviceName;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual bool GetAudioDevice(bool is_input, const std::string& name,
|
||||||
|
Device* out);
|
||||||
|
virtual bool GetDefaultVideoCaptureDevice(Device* device);
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool GetAudioDevicesByPlatform(bool input, std::vector<Device>* devs);
|
||||||
|
|
||||||
|
bool initialized_;
|
||||||
|
#ifdef WIN32
|
||||||
|
bool need_couninitialize_;
|
||||||
|
#endif
|
||||||
|
DeviceWatcher* watcher_;
|
||||||
|
#ifdef LINUX_SOUND_USED
|
||||||
|
SoundSystemHandle sound_system_;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace cricket
|
||||||
|
|
||||||
|
#endif // TALK_SESSION_PHONE_DEVICEMANAGER_H_
|
||||||
@ -0,0 +1,221 @@
|
|||||||
|
// 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 TALK_SESSION_PHONE_FILEMEDIAENGINE_H_
|
||||||
|
#define TALK_SESSION_PHONE_FILEMEDIAENGINE_H_
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "talk/base/scoped_ptr.h"
|
||||||
|
#include "talk/session/phone/codec.h"
|
||||||
|
#include "talk/session/phone/mediachannel.h"
|
||||||
|
#include "talk/session/phone/mediaengine.h"
|
||||||
|
|
||||||
|
namespace talk_base {
|
||||||
|
class StreamInterface;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace cricket {
|
||||||
|
|
||||||
|
// A media engine contains a capturer, an encoder, and a sender in the sender
|
||||||
|
// side and a receiver, a decoder, and a renderer in the receiver side.
|
||||||
|
// FileMediaEngine simulates the capturer and the encoder via an input RTP dump
|
||||||
|
// stream and simulates the decoder and the renderer via an output RTP dump
|
||||||
|
// stream. Depending on the parameters of the constructor, FileMediaEngine can
|
||||||
|
// act as file voice engine, file video engine, or both. Currently, we use
|
||||||
|
// only the RTP dump packets. TODO: Enable RTCP packets.
|
||||||
|
class FileMediaEngine : public MediaEngine {
|
||||||
|
public:
|
||||||
|
FileMediaEngine() {}
|
||||||
|
virtual ~FileMediaEngine() {}
|
||||||
|
|
||||||
|
// Set the file name of the input or output RTP dump for voice or video.
|
||||||
|
// Should be called before the channel is created.
|
||||||
|
void set_voice_input_filename(const std::string& filename) {
|
||||||
|
voice_input_filename_ = filename;
|
||||||
|
}
|
||||||
|
void set_voice_output_filename(const std::string& filename) {
|
||||||
|
voice_output_filename_ = filename;
|
||||||
|
}
|
||||||
|
void set_video_input_filename(const std::string& filename) {
|
||||||
|
video_input_filename_ = filename;
|
||||||
|
}
|
||||||
|
void set_video_output_filename(const std::string& filename) {
|
||||||
|
video_output_filename_ = filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Should be called before codecs() and video_codecs() are called. We need to
|
||||||
|
// set the voice and video codecs; otherwise, Jingle initiation will fail.
|
||||||
|
void set_voice_codecs(const std::vector<AudioCodec>& codecs) {
|
||||||
|
voice_codecs_ = codecs;
|
||||||
|
}
|
||||||
|
void set_video_codecs(const std::vector<VideoCodec>& codecs) {
|
||||||
|
video_codecs_ = codecs;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implement pure virtual methods of MediaEngine.
|
||||||
|
virtual bool Init() { return true; }
|
||||||
|
virtual void Terminate() {}
|
||||||
|
virtual int GetCapabilities();
|
||||||
|
virtual VoiceMediaChannel* CreateChannel();
|
||||||
|
virtual VideoMediaChannel* CreateVideoChannel(VoiceMediaChannel* voice_ch);
|
||||||
|
virtual SoundclipMedia* CreateSoundclip() { return NULL; }
|
||||||
|
virtual bool SetAudioOptions(int options) { return true; }
|
||||||
|
virtual bool SetVideoOptions(int options) { return true; }
|
||||||
|
virtual bool SetDefaultVideoEncoderConfig(const VideoEncoderConfig& config) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
virtual bool SetSoundDevices(const Device* in_dev, const Device* out_dev) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
virtual bool SetVideoCaptureDevice(const Device* cam_device) { return true; }
|
||||||
|
virtual bool GetOutputVolume(int* level) { *level = 0; return true; }
|
||||||
|
virtual bool SetOutputVolume(int level) { return true; }
|
||||||
|
virtual int GetInputLevel() { return 0; }
|
||||||
|
virtual bool SetLocalMonitor(bool enable) { return true; }
|
||||||
|
virtual bool SetLocalRenderer(VideoRenderer* renderer) { return true; }
|
||||||
|
// TODO: control channel send?
|
||||||
|
virtual CaptureResult SetVideoCapture(bool capture) { return CR_SUCCESS; }
|
||||||
|
virtual const std::vector<AudioCodec>& audio_codecs() {
|
||||||
|
return voice_codecs_;
|
||||||
|
}
|
||||||
|
virtual const std::vector<VideoCodec>& video_codecs() {
|
||||||
|
return video_codecs_;
|
||||||
|
}
|
||||||
|
virtual bool FindAudioCodec(const AudioCodec& codec) { return true; }
|
||||||
|
virtual bool FindVideoCodec(const VideoCodec& codec) { return true; }
|
||||||
|
virtual void SetVoiceLogging(int min_sev, const char* filter) {}
|
||||||
|
virtual void SetVideoLogging(int min_sev, const char* filter) {}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string voice_input_filename_;
|
||||||
|
std::string voice_output_filename_;
|
||||||
|
std::string video_input_filename_;
|
||||||
|
std::string video_output_filename_;
|
||||||
|
std::vector<AudioCodec> voice_codecs_;
|
||||||
|
std::vector<VideoCodec> video_codecs_;
|
||||||
|
|
||||||
|
DISALLOW_COPY_AND_ASSIGN(FileMediaEngine);
|
||||||
|
};
|
||||||
|
|
||||||
|
class RtpSenderReceiver; // Forward declaration. Defined in the .cc file.
|
||||||
|
|
||||||
|
class FileVoiceChannel : public VoiceMediaChannel {
|
||||||
|
public:
|
||||||
|
FileVoiceChannel(const std::string& in_file, const std::string& out_file);
|
||||||
|
virtual ~FileVoiceChannel();
|
||||||
|
|
||||||
|
// Implement pure virtual methods of VoiceMediaChannel.
|
||||||
|
virtual bool SetRecvCodecs(const std::vector<AudioCodec>& codecs) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
virtual bool SetSendCodecs(const std::vector<AudioCodec>& codecs);
|
||||||
|
virtual bool SetRecvRtpHeaderExtensions(
|
||||||
|
const std::vector<RtpHeaderExtension>& extensions) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
virtual bool SetSendRtpHeaderExtensions(
|
||||||
|
const std::vector<RtpHeaderExtension>& extensions) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
virtual bool SetPlayout(bool playout) { return true; }
|
||||||
|
virtual bool SetSend(SendFlags flag);
|
||||||
|
virtual bool AddStream(uint32 ssrc) { return true; }
|
||||||
|
virtual bool RemoveStream(uint32 ssrc) { return true; }
|
||||||
|
virtual bool GetActiveStreams(AudioInfo::StreamList* actives) { return true; }
|
||||||
|
virtual int GetOutputLevel() { return 0; }
|
||||||
|
virtual bool SetRingbackTone(const char* buf, int len) { return true; }
|
||||||
|
virtual bool PlayRingbackTone(uint32 ssrc, bool play, bool loop) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
virtual bool PressDTMF(int event, bool playout) { return true; }
|
||||||
|
virtual bool GetStats(VoiceMediaInfo* info) { return true; }
|
||||||
|
|
||||||
|
// Implement pure virtual methods of MediaChannel.
|
||||||
|
virtual void OnPacketReceived(talk_base::Buffer* packet);
|
||||||
|
virtual void OnRtcpReceived(talk_base::Buffer* packet) {}
|
||||||
|
virtual void SetSendSsrc(uint32 id) {} // TODO: change RTP packet?
|
||||||
|
virtual bool SetRtcpCName(const std::string& cname) { return true; }
|
||||||
|
virtual bool Mute(bool on) { return false; }
|
||||||
|
virtual bool SetSendBandwidth(bool autobw, int bps) { return true; }
|
||||||
|
virtual bool SetOptions(int options) { return true; }
|
||||||
|
virtual int GetMediaChannelId() { return -1; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
talk_base::scoped_ptr<RtpSenderReceiver> rtp_sender_receiver_;
|
||||||
|
DISALLOW_COPY_AND_ASSIGN(FileVoiceChannel);
|
||||||
|
};
|
||||||
|
|
||||||
|
class FileVideoChannel : public VideoMediaChannel {
|
||||||
|
public:
|
||||||
|
FileVideoChannel(const std::string& in_file, const std::string& out_file);
|
||||||
|
virtual ~FileVideoChannel();
|
||||||
|
|
||||||
|
// Implement pure virtual methods of VideoMediaChannel.
|
||||||
|
virtual bool SetRecvCodecs(const std::vector<VideoCodec>& codecs) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
virtual bool SetSendCodecs(const std::vector<VideoCodec>& codecs);
|
||||||
|
virtual bool SetRecvRtpHeaderExtensions(
|
||||||
|
const std::vector<RtpHeaderExtension>& extensions) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
virtual bool SetSendRtpHeaderExtensions(
|
||||||
|
const std::vector<RtpHeaderExtension>& extensions) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
virtual bool SetRender(bool render) { return true; }
|
||||||
|
virtual bool SetSend(bool send);
|
||||||
|
virtual bool AddStream(uint32 ssrc, uint32 voice_ssrc) { return true; }
|
||||||
|
virtual bool RemoveStream(uint32 ssrc) { return true; }
|
||||||
|
virtual bool SetRenderer(uint32 ssrc, VideoRenderer* renderer) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
virtual bool SetExternalRenderer(uint32 ssrc, void* renderer) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
virtual bool GetStats(VideoMediaInfo* info) { return true; }
|
||||||
|
virtual bool SendIntraFrame() { return false; }
|
||||||
|
virtual bool RequestIntraFrame() { return false; }
|
||||||
|
|
||||||
|
// Implement pure virtual methods of MediaChannel.
|
||||||
|
virtual void OnPacketReceived(talk_base::Buffer* packet);
|
||||||
|
virtual void OnRtcpReceived(talk_base::Buffer* packet) {}
|
||||||
|
virtual void SetSendSsrc(uint32 id) {} // TODO: change RTP packet?
|
||||||
|
virtual bool SetRtcpCName(const std::string& cname) { return true; }
|
||||||
|
virtual bool Mute(bool on) { return false; }
|
||||||
|
virtual bool SetSendBandwidth(bool autobw, int bps) { return true; }
|
||||||
|
virtual bool SetOptions(int options) { return true; }
|
||||||
|
virtual int GetMediaChannelId() { return -1; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
talk_base::scoped_ptr<RtpSenderReceiver> rtp_sender_receiver_;
|
||||||
|
DISALLOW_COPY_AND_ASSIGN(FileVideoChannel);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace cricket
|
||||||
|
|
||||||
|
#endif // TALK_SESSION_PHONE_FILEMEDIAENGINE_H_
|
||||||
@ -0,0 +1,501 @@
|
|||||||
|
/*
|
||||||
|
* libjingle
|
||||||
|
* Copyright 2004--2010, Google Inc.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
* 3. The name of the author may not be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||||
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||||
|
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||||
|
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||||
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||||
|
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||||
|
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TALK_SESSION_PHONE_MEDIACHANNEL_H_
|
||||||
|
#define TALK_SESSION_PHONE_MEDIACHANNEL_H_
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "talk/base/basictypes.h"
|
||||||
|
#include "talk/base/sigslot.h"
|
||||||
|
#include "talk/base/socket.h"
|
||||||
|
#include "talk/session/phone/codec.h"
|
||||||
|
// TODO: re-evaluate this include
|
||||||
|
#include "talk/session/phone/audiomonitor.h"
|
||||||
|
|
||||||
|
namespace talk_base {
|
||||||
|
class Buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace flute {
|
||||||
|
class MagicCamVideoRenderer;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace cricket {
|
||||||
|
|
||||||
|
const int kMinRtpHeaderExtensionId = 1;
|
||||||
|
const int kMaxRtpHeaderExtensionId = 255;
|
||||||
|
|
||||||
|
struct RtpHeaderExtension {
|
||||||
|
RtpHeaderExtension(const std::string& u, int i) : uri(u), id(i) {}
|
||||||
|
std::string uri;
|
||||||
|
int id;
|
||||||
|
// TODO: SendRecv direction;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum VoiceMediaChannelOptions {
|
||||||
|
OPT_CONFERENCE = 0x10000, // tune the audio stream for conference mode
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
enum VideoMediaChannelOptions {
|
||||||
|
OPT_INTERPOLATE = 0x10000 // Increase the output framerate by 2x by
|
||||||
|
// interpolating frames
|
||||||
|
};
|
||||||
|
|
||||||
|
class MediaChannel : public sigslot::has_slots<> {
|
||||||
|
public:
|
||||||
|
class NetworkInterface {
|
||||||
|
public:
|
||||||
|
enum SocketType { ST_RTP, ST_RTCP };
|
||||||
|
virtual bool SendPacket(talk_base::Buffer* packet) = 0;
|
||||||
|
virtual bool SendRtcp(talk_base::Buffer* packet) = 0;
|
||||||
|
virtual int SetOption(SocketType type, talk_base::Socket::Option opt,
|
||||||
|
int option) = 0;
|
||||||
|
virtual ~NetworkInterface() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
MediaChannel() : network_interface_(NULL) {}
|
||||||
|
virtual ~MediaChannel() {}
|
||||||
|
|
||||||
|
// Gets/sets the abstract inteface class for sending RTP/RTCP data.
|
||||||
|
NetworkInterface *network_interface() { return network_interface_; }
|
||||||
|
virtual void SetInterface(NetworkInterface *iface) {
|
||||||
|
network_interface_ = iface;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Called when a RTP packet is received.
|
||||||
|
virtual void OnPacketReceived(talk_base::Buffer* packet) = 0;
|
||||||
|
// Called when a RTCP packet is received.
|
||||||
|
virtual void OnRtcpReceived(talk_base::Buffer* packet) = 0;
|
||||||
|
// Sets the SSRC to be used for outgoing data.
|
||||||
|
virtual void SetSendSsrc(uint32 id) = 0;
|
||||||
|
// Set the CNAME of RTCP
|
||||||
|
virtual bool SetRtcpCName(const std::string& cname) = 0;
|
||||||
|
// Mutes the channel.
|
||||||
|
virtual bool Mute(bool on) = 0;
|
||||||
|
|
||||||
|
// Sets the RTP extension headers and IDs to use when sending RTP.
|
||||||
|
virtual bool SetRecvRtpHeaderExtensions(
|
||||||
|
const std::vector<RtpHeaderExtension>& extensions) = 0;
|
||||||
|
virtual bool SetSendRtpHeaderExtensions(
|
||||||
|
const std::vector<RtpHeaderExtension>& extensions) = 0;
|
||||||
|
// Sets the rate control to use when sending data.
|
||||||
|
virtual bool SetSendBandwidth(bool autobw, int bps) = 0;
|
||||||
|
// Sets the media options to use.
|
||||||
|
virtual bool SetOptions(int options) = 0;
|
||||||
|
// Gets the Rtc channel id
|
||||||
|
virtual int GetMediaChannelId() = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
NetworkInterface *network_interface_;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum SendFlags {
|
||||||
|
SEND_NOTHING,
|
||||||
|
SEND_RINGBACKTONE,
|
||||||
|
SEND_MICROPHONE
|
||||||
|
};
|
||||||
|
|
||||||
|
struct VoiceSenderInfo {
|
||||||
|
uint32 ssrc;
|
||||||
|
int bytes_sent;
|
||||||
|
int packets_sent;
|
||||||
|
int packets_lost;
|
||||||
|
float fraction_lost;
|
||||||
|
int ext_seqnum;
|
||||||
|
int rtt_ms;
|
||||||
|
int jitter_ms;
|
||||||
|
int audio_level;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct VoiceReceiverInfo {
|
||||||
|
uint32 ssrc;
|
||||||
|
int bytes_rcvd;
|
||||||
|
int packets_rcvd;
|
||||||
|
int packets_lost;
|
||||||
|
float fraction_lost;
|
||||||
|
int ext_seqnum;
|
||||||
|
int jitter_ms;
|
||||||
|
int jitter_buffer_ms;
|
||||||
|
int jitter_buffer_preferred_ms;
|
||||||
|
int delay_estimate_ms;
|
||||||
|
int audio_level;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct VideoSenderInfo {
|
||||||
|
uint32 ssrc;
|
||||||
|
int bytes_sent;
|
||||||
|
int packets_sent;
|
||||||
|
int packets_cached;
|
||||||
|
int packets_lost;
|
||||||
|
float fraction_lost;
|
||||||
|
int firs_rcvd;
|
||||||
|
int nacks_rcvd;
|
||||||
|
int rtt_ms;
|
||||||
|
int frame_width;
|
||||||
|
int frame_height;
|
||||||
|
int framerate_input;
|
||||||
|
int framerate_sent;
|
||||||
|
int nominal_bitrate;
|
||||||
|
int preferred_bitrate;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct VideoReceiverInfo {
|
||||||
|
uint32 ssrc;
|
||||||
|
int bytes_rcvd;
|
||||||
|
// vector<int> layer_bytes_rcvd;
|
||||||
|
int packets_rcvd;
|
||||||
|
int packets_lost;
|
||||||
|
int packets_concealed;
|
||||||
|
float fraction_lost;
|
||||||
|
int firs_sent;
|
||||||
|
int nacks_sent;
|
||||||
|
int frame_width;
|
||||||
|
int frame_height;
|
||||||
|
int framerate_rcvd;
|
||||||
|
int framerate_decoded;
|
||||||
|
int framerate_output;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BandwidthEstimationInfo {
|
||||||
|
int available_send_bandwidth;
|
||||||
|
int available_recv_bandwidth;
|
||||||
|
int target_enc_bitrate;
|
||||||
|
int actual_enc_bitrate;
|
||||||
|
int retransmit_bitrate;
|
||||||
|
int transmit_bitrate;
|
||||||
|
int bucket_delay;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct VoiceMediaInfo {
|
||||||
|
void Clear() {
|
||||||
|
senders.clear();
|
||||||
|
receivers.clear();
|
||||||
|
}
|
||||||
|
std::vector<VoiceSenderInfo> senders;
|
||||||
|
std::vector<VoiceReceiverInfo> receivers;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct VideoMediaInfo {
|
||||||
|
void Clear() {
|
||||||
|
senders.clear();
|
||||||
|
receivers.clear();
|
||||||
|
bw_estimations.clear();
|
||||||
|
}
|
||||||
|
std::vector<VideoSenderInfo> senders;
|
||||||
|
std::vector<VideoReceiverInfo> receivers;
|
||||||
|
std::vector<BandwidthEstimationInfo> bw_estimations;
|
||||||
|
};
|
||||||
|
|
||||||
|
class VoiceMediaChannel : public MediaChannel {
|
||||||
|
public:
|
||||||
|
enum Error {
|
||||||
|
ERROR_NONE = 0, // No error.
|
||||||
|
ERROR_OTHER, // Other errors.
|
||||||
|
ERROR_REC_DEVICE_OPEN_FAILED = 100, // Could not open mic.
|
||||||
|
ERROR_REC_DEVICE_MUTED, // Mic was muted by OS.
|
||||||
|
ERROR_REC_DEVICE_SILENT, // No background noise picked up.
|
||||||
|
ERROR_REC_DEVICE_SATURATION, // Mic input is clipping.
|
||||||
|
ERROR_REC_DEVICE_REMOVED, // Mic was removed while active.
|
||||||
|
ERROR_REC_RUNTIME_ERROR, // Processing is encountering errors.
|
||||||
|
ERROR_REC_SRTP_ERROR, // Generic SRTP failure.
|
||||||
|
ERROR_REC_SRTP_AUTH_FAILED, // Failed to authenticate packets.
|
||||||
|
ERROR_REC_TYPING_NOISE_DETECTED, // Typing noise is detected.
|
||||||
|
ERROR_PLAY_DEVICE_OPEN_FAILED = 200, // Could not open playout.
|
||||||
|
ERROR_PLAY_DEVICE_MUTED, // Playout muted by OS.
|
||||||
|
ERROR_PLAY_DEVICE_REMOVED, // Playout removed while active.
|
||||||
|
ERROR_PLAY_RUNTIME_ERROR, // Errors in voice processing.
|
||||||
|
ERROR_PLAY_SRTP_ERROR, // Generic SRTP failure.
|
||||||
|
ERROR_PLAY_SRTP_AUTH_FAILED, // Failed to authenticate packets.
|
||||||
|
ERROR_PLAY_SRTP_REPLAY, // Packet replay detected.
|
||||||
|
};
|
||||||
|
|
||||||
|
VoiceMediaChannel() {}
|
||||||
|
virtual ~VoiceMediaChannel() {}
|
||||||
|
// Sets the codecs/payload types to be used for incoming media.
|
||||||
|
virtual bool SetRecvCodecs(const std::vector<AudioCodec>& codecs) = 0;
|
||||||
|
// Sets the codecs/payload types to be used for outgoing media.
|
||||||
|
virtual bool SetSendCodecs(const std::vector<AudioCodec>& codecs) = 0;
|
||||||
|
// Starts or stops playout of received audio.
|
||||||
|
virtual bool SetPlayout(bool playout) = 0;
|
||||||
|
// Starts or stops sending (and potentially capture) of local audio.
|
||||||
|
virtual bool SetSend(SendFlags flag) = 0;
|
||||||
|
// Adds a new receive-only stream with the specified SSRC.
|
||||||
|
virtual bool AddStream(uint32 ssrc) = 0;
|
||||||
|
// Removes a stream added with AddStream.
|
||||||
|
virtual bool RemoveStream(uint32 ssrc) = 0;
|
||||||
|
// Gets current energy levels for all incoming streams.
|
||||||
|
virtual bool GetActiveStreams(AudioInfo::StreamList* actives) = 0;
|
||||||
|
// Get the current energy level for the outgoing stream.
|
||||||
|
virtual int GetOutputLevel() = 0;
|
||||||
|
// Specifies a ringback tone to be played during call setup.
|
||||||
|
virtual bool SetRingbackTone(const char *buf, int len) = 0;
|
||||||
|
// Plays or stops the aforementioned ringback tone
|
||||||
|
virtual bool PlayRingbackTone(uint32 ssrc, bool play, bool loop) = 0;
|
||||||
|
// Sends a out-of-band DTMF signal using the specified event.
|
||||||
|
virtual bool PressDTMF(int event, bool playout) = 0;
|
||||||
|
// Gets quality stats for the channel.
|
||||||
|
virtual bool GetStats(VoiceMediaInfo* info) = 0;
|
||||||
|
// Gets last reported error for this media channel.
|
||||||
|
virtual void GetLastMediaError(uint32* ssrc,
|
||||||
|
VoiceMediaChannel::Error* error) {
|
||||||
|
ASSERT(error != NULL);
|
||||||
|
*error = ERROR_NONE;
|
||||||
|
}
|
||||||
|
// Signal errors from MediaChannel. Arguments are:
|
||||||
|
// ssrc(uint32), and error(VoiceMediaChannel::Error).
|
||||||
|
sigslot::signal2<uint32, VoiceMediaChannel::Error> SignalMediaError;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Represents a YUV420 (a.k.a. I420) video frame.
|
||||||
|
class VideoFrame {
|
||||||
|
friend class flute::MagicCamVideoRenderer;
|
||||||
|
|
||||||
|
public:
|
||||||
|
VideoFrame() : rendered_(false) {}
|
||||||
|
|
||||||
|
virtual ~VideoFrame() {}
|
||||||
|
|
||||||
|
virtual size_t GetWidth() const = 0;
|
||||||
|
virtual size_t GetHeight() const = 0;
|
||||||
|
virtual const uint8 *GetYPlane() const = 0;
|
||||||
|
virtual const uint8 *GetUPlane() const = 0;
|
||||||
|
virtual const uint8 *GetVPlane() const = 0;
|
||||||
|
virtual uint8 *GetYPlane() = 0;
|
||||||
|
virtual uint8 *GetUPlane() = 0;
|
||||||
|
virtual uint8 *GetVPlane() = 0;
|
||||||
|
virtual int32 GetYPitch() const = 0;
|
||||||
|
virtual int32 GetUPitch() const = 0;
|
||||||
|
virtual int32 GetVPitch() const = 0;
|
||||||
|
|
||||||
|
// For retrieving the aspect ratio of each pixel. Usually this is 1x1, but
|
||||||
|
// the aspect_ratio_idc parameter of H.264 can specify non-square pixels.
|
||||||
|
virtual size_t GetPixelWidth() const = 0;
|
||||||
|
virtual size_t GetPixelHeight() const = 0;
|
||||||
|
|
||||||
|
// TODO: Add a fourcc format here and probably combine VideoFrame
|
||||||
|
// with CapturedFrame.
|
||||||
|
virtual int64 GetElapsedTime() const = 0;
|
||||||
|
virtual int64 GetTimeStamp() const = 0;
|
||||||
|
virtual void SetElapsedTime(int64 elapsed_time) = 0;
|
||||||
|
virtual void SetTimeStamp(int64 time_stamp) = 0;
|
||||||
|
|
||||||
|
// Make a copy of the frame. The frame buffer itself may not be copied,
|
||||||
|
// in which case both the current and new VideoFrame will share a single
|
||||||
|
// reference-counted frame buffer.
|
||||||
|
virtual VideoFrame *Copy() const = 0;
|
||||||
|
|
||||||
|
// Writes the frame into the given frame buffer, provided that it is of
|
||||||
|
// sufficient size. Returns the frame's actual size, regardless of whether
|
||||||
|
// it was written or not (like snprintf). If there is insufficient space,
|
||||||
|
// nothing is written.
|
||||||
|
virtual size_t CopyToBuffer(uint8 *buffer, size_t size) const = 0;
|
||||||
|
|
||||||
|
// Converts the I420 data to RGB of a certain type such as ARGB and ABGR.
|
||||||
|
// Returns the frame's actual size, regardless of whether it was written or
|
||||||
|
// not (like snprintf). Parameters size and pitch_rgb are in units of bytes.
|
||||||
|
// If there is insufficient space, nothing is written.
|
||||||
|
virtual size_t ConvertToRgbBuffer(uint32 to_fourcc, uint8 *buffer,
|
||||||
|
size_t size, size_t pitch_rgb) const = 0;
|
||||||
|
|
||||||
|
// Writes the frame into the given planes, stretched to the given width and
|
||||||
|
// height. The parameter "interpolate" controls whether to interpolate or just
|
||||||
|
// take the nearest-point. The parameter "crop" controls whether to crop this
|
||||||
|
// frame to the aspect ratio of the given dimensions before stretching.
|
||||||
|
virtual void StretchToPlanes(uint8 *y, uint8 *u, uint8 *v,
|
||||||
|
int32 pitchY, int32 pitchU, int32 pitchV,
|
||||||
|
size_t width, size_t height,
|
||||||
|
bool interpolate, bool crop) const = 0;
|
||||||
|
|
||||||
|
// Writes the frame into the given frame buffer, stretched to the given width
|
||||||
|
// and height, provided that it is of sufficient size. Returns the frame's
|
||||||
|
// actual size, regardless of whether it was written or not (like snprintf).
|
||||||
|
// If there is insufficient space, nothing is written. The parameter
|
||||||
|
// "interpolate" controls whether to interpolate or just take the
|
||||||
|
// nearest-point. The parameter "crop" controls whether to crop this frame to
|
||||||
|
// the aspect ratio of the given dimensions before stretching.
|
||||||
|
virtual size_t StretchToBuffer(size_t w, size_t h, uint8 *buffer, size_t size,
|
||||||
|
bool interpolate, bool crop) const = 0;
|
||||||
|
|
||||||
|
// Writes the frame into the target VideoFrame, stretched to the size of that
|
||||||
|
// frame. The parameter "interpolate" controls whether to interpolate or just
|
||||||
|
// take the nearest-point. The parameter "crop" controls whether to crop this
|
||||||
|
// frame to the aspect ratio of the target frame before stretching.
|
||||||
|
virtual void StretchToFrame(VideoFrame *target, bool interpolate,
|
||||||
|
bool crop) const = 0;
|
||||||
|
|
||||||
|
// Stretches the frame to the given size, creating a new VideoFrame object to
|
||||||
|
// hold it. The parameter "interpolate" controls whether to interpolate or
|
||||||
|
// just take the nearest-point. The parameter "crop" controls whether to crop
|
||||||
|
// this frame to the aspect ratio of the given dimensions before stretching.
|
||||||
|
virtual VideoFrame *Stretch(size_t w, size_t h, bool interpolate,
|
||||||
|
bool crop) const = 0;
|
||||||
|
|
||||||
|
// Size of an I420 image of given dimensions when stored as a frame buffer.
|
||||||
|
static size_t SizeOf(size_t w, size_t h) {
|
||||||
|
return w * h + ((w + 1) / 2) * ((h + 1) / 2) * 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// The frame needs to be rendered to magiccam only once.
|
||||||
|
// TODO: Remove this flag once magiccam rendering is fully replaced
|
||||||
|
// by client3d rendering.
|
||||||
|
mutable bool rendered_;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Simple subclass for use in mocks.
|
||||||
|
class NullVideoFrame : public VideoFrame {
|
||||||
|
public:
|
||||||
|
virtual size_t GetWidth() const { return 0; }
|
||||||
|
virtual size_t GetHeight() const { return 0; }
|
||||||
|
virtual const uint8 *GetYPlane() const { return NULL; }
|
||||||
|
virtual const uint8 *GetUPlane() const { return NULL; }
|
||||||
|
virtual const uint8 *GetVPlane() const { return NULL; }
|
||||||
|
virtual uint8 *GetYPlane() { return NULL; }
|
||||||
|
virtual uint8 *GetUPlane() { return NULL; }
|
||||||
|
virtual uint8 *GetVPlane() { return NULL; }
|
||||||
|
virtual int32 GetYPitch() const { return 0; }
|
||||||
|
virtual int32 GetUPitch() const { return 0; }
|
||||||
|
virtual int32 GetVPitch() const { return 0; }
|
||||||
|
|
||||||
|
virtual size_t GetPixelWidth() const { return 1; }
|
||||||
|
virtual size_t GetPixelHeight() const { return 1; }
|
||||||
|
virtual int64 GetElapsedTime() const { return 0; }
|
||||||
|
virtual int64 GetTimeStamp() const { return 0; }
|
||||||
|
virtual void SetElapsedTime(int64 elapsed_time) {}
|
||||||
|
virtual void SetTimeStamp(int64 time_stamp) {}
|
||||||
|
|
||||||
|
virtual VideoFrame *Copy() const {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual size_t CopyToBuffer(uint8 *buffer, size_t size) const {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual size_t ConvertToRgbBuffer(uint32 to_fourcc, uint8 *buffer,
|
||||||
|
size_t size, size_t pitch_rgb) const {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void StretchToPlanes(uint8 *y, uint8 *u, uint8 *v,
|
||||||
|
int32 pitchY, int32 pitchU, int32 pitchV,
|
||||||
|
size_t width, size_t height,
|
||||||
|
bool interpolate, bool crop) const {
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual size_t StretchToBuffer(size_t w, size_t h, uint8 *buffer, size_t size,
|
||||||
|
bool interpolate, bool crop) const {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void StretchToFrame(VideoFrame *target, bool interpolate,
|
||||||
|
bool crop) const {
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual VideoFrame *Stretch(size_t w, size_t h, bool interpolate,
|
||||||
|
bool crop) const {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Abstract interface for rendering VideoFrames.
|
||||||
|
class VideoRenderer {
|
||||||
|
public:
|
||||||
|
virtual ~VideoRenderer() {}
|
||||||
|
// Called when the video has changed size.
|
||||||
|
virtual bool SetSize(int width, int height, int reserved) = 0;
|
||||||
|
// Called when a new frame is available for display.
|
||||||
|
virtual bool RenderFrame(const VideoFrame *frame) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Simple implementation for use in tests.
|
||||||
|
class NullVideoRenderer : public VideoRenderer {
|
||||||
|
virtual bool SetSize(int width, int height, int reserved) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// Called when a new frame is available for display.
|
||||||
|
virtual bool RenderFrame(const VideoFrame *frame) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class VideoMediaChannel : public MediaChannel {
|
||||||
|
public:
|
||||||
|
enum Error {
|
||||||
|
ERROR_NONE = 0, // No error.
|
||||||
|
ERROR_OTHER, // Other errors.
|
||||||
|
ERROR_REC_DEVICE_OPEN_FAILED = 100, // Could not open camera.
|
||||||
|
ERROR_REC_DEVICE_NO_DEVICE, // No camera.
|
||||||
|
ERROR_REC_DEVICE_IN_USE, // Device is in already use.
|
||||||
|
ERROR_REC_DEVICE_REMOVED, // Device is removed.
|
||||||
|
ERROR_REC_SRTP_ERROR, // Generic sender SRTP failure.
|
||||||
|
ERROR_REC_SRTP_AUTH_FAILED, // Failed to authenticate packets.
|
||||||
|
ERROR_PLAY_SRTP_ERROR = 200, // Generic receiver SRTP failure.
|
||||||
|
ERROR_PLAY_SRTP_AUTH_FAILED, // Failed to authenticate packets.
|
||||||
|
ERROR_PLAY_SRTP_REPLAY, // Packet replay detected.
|
||||||
|
};
|
||||||
|
|
||||||
|
VideoMediaChannel() { renderer_ = NULL; }
|
||||||
|
virtual ~VideoMediaChannel() {}
|
||||||
|
// Sets the codecs/payload types to be used for incoming media.
|
||||||
|
virtual bool SetRecvCodecs(const std::vector<VideoCodec> &codecs) = 0;
|
||||||
|
// Sets the codecs/payload types to be used for outgoing media.
|
||||||
|
virtual bool SetSendCodecs(const std::vector<VideoCodec> &codecs) = 0;
|
||||||
|
// Starts or stops playout of received video.
|
||||||
|
virtual bool SetRender(bool render) = 0;
|
||||||
|
// Starts or stops transmission (and potentially capture) of local video.
|
||||||
|
virtual bool SetSend(bool send) = 0;
|
||||||
|
// Adds a new receive-only stream with the specified SSRC.
|
||||||
|
virtual bool AddStream(uint32 ssrc, uint32 voice_ssrc) = 0;
|
||||||
|
// Removes a stream added with AddStream.
|
||||||
|
virtual bool RemoveStream(uint32 ssrc) = 0;
|
||||||
|
// Sets the renderer object to be used for the specified stream.
|
||||||
|
// If SSRC is 0, the renderer is used for the 'default' stream.
|
||||||
|
virtual bool SetRenderer(uint32 ssrc, VideoRenderer* renderer) = 0;
|
||||||
|
// Sets the renderer object to be used for the specified stream.
|
||||||
|
// If SSRC is 0, the renderer is used for the 'default' stream.
|
||||||
|
virtual bool SetExternalRenderer(uint32 ssrc, void* renderer) = 0;
|
||||||
|
// Gets quality stats for the channel.
|
||||||
|
virtual bool GetStats(VideoMediaInfo* info) = 0;
|
||||||
|
|
||||||
|
// Send an intra frame to the receivers.
|
||||||
|
virtual bool SendIntraFrame() = 0;
|
||||||
|
// Reuqest each of the remote senders to send an intra frame.
|
||||||
|
virtual bool RequestIntraFrame() = 0;
|
||||||
|
|
||||||
|
sigslot::signal2<uint32, Error> SignalMediaError;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
VideoRenderer *renderer_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace cricket
|
||||||
|
|
||||||
|
#endif // TALK_SESSION_PHONE_MEDIACHANNEL_H_
|
||||||
@ -0,0 +1,58 @@
|
|||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifdef HAVE_WEBRTC
|
||||||
|
#include "talk/app/voicemediaengine.h"
|
||||||
|
#include "talk/app/videomediaengine.h"
|
||||||
|
#endif
|
||||||
|
#include "talk/session/phone/mediaengine.h"
|
||||||
|
#ifdef HAVE_LINPHONE
|
||||||
|
#include "talk/session/phone/linphonemediaengine.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
namespace cricket {
|
||||||
|
|
||||||
|
#ifdef HAVE_WEBRTC
|
||||||
|
template<>
|
||||||
|
CompositeMediaEngine<webrtc::RtcVoiceEngine, webrtc::RtcVideoEngine>
|
||||||
|
::CompositeMediaEngine() : video_(&voice_) {
|
||||||
|
}
|
||||||
|
MediaEngine* MediaEngine::Create() {
|
||||||
|
return new CompositeMediaEngine<webrtc::RtcVoiceEngine,
|
||||||
|
webrtc::RtcVideoEngine>();
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
MediaEngine* MediaEngine::Create() {
|
||||||
|
#ifdef HAVE_LINPHONE
|
||||||
|
return new LinphoneMediaEngine("", "");
|
||||||
|
#else
|
||||||
|
return new NullMediaEngine();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}; // namespace cricket
|
||||||
@ -0,0 +1,328 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TALK_SESSION_PHONE_MEDIAENGINE_H_
|
||||||
|
#define TALK_SESSION_PHONE_MEDIAENGINE_H_
|
||||||
|
|
||||||
|
#ifdef OSX
|
||||||
|
#include <CoreAudio/CoreAudio.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "talk/base/sigslotrepeater.h"
|
||||||
|
#include "talk/session/phone/codec.h"
|
||||||
|
#include "talk/session/phone/devicemanager.h"
|
||||||
|
#include "talk/session/phone/mediachannel.h"
|
||||||
|
#include "talk/session/phone/videocommon.h"
|
||||||
|
|
||||||
|
namespace cricket {
|
||||||
|
|
||||||
|
// A class for playing out soundclips.
|
||||||
|
class SoundclipMedia {
|
||||||
|
public:
|
||||||
|
enum SoundclipFlags {
|
||||||
|
SF_LOOP = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
virtual ~SoundclipMedia() {}
|
||||||
|
|
||||||
|
// Plays a sound out to the speakers with the given audio stream. The stream
|
||||||
|
// must be 16-bit little-endian 16 kHz PCM. If a stream is already playing
|
||||||
|
// on this SoundclipMedia, it is stopped. If clip is NULL, nothing is played.
|
||||||
|
// Returns whether it was successful.
|
||||||
|
virtual bool PlaySound(const char *clip, int len, int flags) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
// MediaEngine is an abstraction of a media engine which can be subclassed
|
||||||
|
// to support different media componentry backends. It supports voice and
|
||||||
|
// video operations in the same class to facilitate proper synchronization
|
||||||
|
// between both media types.
|
||||||
|
class MediaEngine {
|
||||||
|
public:
|
||||||
|
// TODO: Move this to a global location (also used in DeviceManager)
|
||||||
|
// Capabilities of the media engine.
|
||||||
|
enum Capabilities {
|
||||||
|
AUDIO_RECV = 1 << 0,
|
||||||
|
AUDIO_SEND = 1 << 1,
|
||||||
|
VIDEO_RECV = 1 << 2,
|
||||||
|
VIDEO_SEND = 1 << 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Bitmask flags for options that may be supported by the media engine
|
||||||
|
// implementation
|
||||||
|
enum AudioOptions {
|
||||||
|
ECHO_CANCELLATION = 1 << 0,
|
||||||
|
AUTO_GAIN_CONTROL = 1 << 1,
|
||||||
|
DEFAULT_AUDIO_OPTIONS = ECHO_CANCELLATION | AUTO_GAIN_CONTROL
|
||||||
|
};
|
||||||
|
enum VideoOptions {
|
||||||
|
};
|
||||||
|
|
||||||
|
virtual ~MediaEngine() {}
|
||||||
|
static MediaEngine* Create();
|
||||||
|
|
||||||
|
// Initialization
|
||||||
|
// Starts the engine.
|
||||||
|
virtual bool Init() = 0;
|
||||||
|
// Shuts down the engine.
|
||||||
|
virtual void Terminate() = 0;
|
||||||
|
// Returns what the engine is capable of, as a set of Capabilities, above.
|
||||||
|
virtual int GetCapabilities() = 0;
|
||||||
|
|
||||||
|
// MediaChannel creation
|
||||||
|
// Creates a voice media channel. Returns NULL on failure.
|
||||||
|
virtual VoiceMediaChannel *CreateChannel() = 0;
|
||||||
|
// Creates a video media channel, paired with the specified voice channel.
|
||||||
|
// Returns NULL on failure.
|
||||||
|
virtual VideoMediaChannel *CreateVideoChannel(
|
||||||
|
VoiceMediaChannel* voice_media_channel) = 0;
|
||||||
|
|
||||||
|
// Creates a soundclip object for playing sounds on. Returns NULL on failure.
|
||||||
|
virtual SoundclipMedia *CreateSoundclip() = 0;
|
||||||
|
|
||||||
|
// Configuration
|
||||||
|
// Sets global audio options. "options" are from AudioOptions, above.
|
||||||
|
virtual bool SetAudioOptions(int options) = 0;
|
||||||
|
// Sets global video options. "options" are from VideoOptions, above.
|
||||||
|
virtual bool SetVideoOptions(int options) = 0;
|
||||||
|
// Sets the default (maximum) codec/resolution and encoder option to capture
|
||||||
|
// and encode video.
|
||||||
|
virtual bool SetDefaultVideoEncoderConfig(const VideoEncoderConfig& config)
|
||||||
|
= 0;
|
||||||
|
|
||||||
|
// Device selection
|
||||||
|
// TODO: Add method for selecting the soundclip device.
|
||||||
|
virtual bool SetSoundDevices(const Device* in_device,
|
||||||
|
const Device* out_device) = 0;
|
||||||
|
virtual bool SetVideoCaptureDevice(const Device* cam_device) = 0;
|
||||||
|
virtual bool SetVideoRenderer(int channel_id,
|
||||||
|
void* window,
|
||||||
|
unsigned int zOrder,
|
||||||
|
float left,
|
||||||
|
float top,
|
||||||
|
float right,
|
||||||
|
float bottom) = 0;
|
||||||
|
|
||||||
|
// Device configuration
|
||||||
|
// Gets the current speaker volume, as a value between 0 and 255.
|
||||||
|
virtual bool GetOutputVolume(int* level) = 0;
|
||||||
|
// Sets the current speaker volume, as a value between 0 and 255.
|
||||||
|
virtual bool SetOutputVolume(int level) = 0;
|
||||||
|
|
||||||
|
// Local monitoring
|
||||||
|
// Gets the current microphone level, as a value between 0 and 10.
|
||||||
|
virtual int GetInputLevel() = 0;
|
||||||
|
// Starts or stops the local microphone. Useful if local mic info is needed
|
||||||
|
// prior to a call being connected; the mic will be started automatically
|
||||||
|
// when a VoiceMediaChannel starts sending.
|
||||||
|
virtual bool SetLocalMonitor(bool enable) = 0;
|
||||||
|
// Installs a callback for raw frames from the local camera.
|
||||||
|
virtual bool SetLocalRenderer(VideoRenderer* renderer) = 0;
|
||||||
|
// Starts/stops local camera.
|
||||||
|
virtual CaptureResult SetVideoCapture(bool capture) = 0;
|
||||||
|
|
||||||
|
virtual const std::vector<AudioCodec>& audio_codecs() = 0;
|
||||||
|
virtual const std::vector<VideoCodec>& video_codecs() = 0;
|
||||||
|
|
||||||
|
// Logging control
|
||||||
|
virtual void SetVoiceLogging(int min_sev, const char* filter) = 0;
|
||||||
|
virtual void SetVideoLogging(int min_sev, const char* filter) = 0;
|
||||||
|
|
||||||
|
sigslot::repeater1<CaptureResult> SignalVideoCaptureResult;
|
||||||
|
};
|
||||||
|
|
||||||
|
// CompositeMediaEngine constructs a MediaEngine from separate
|
||||||
|
// voice and video engine classes.
|
||||||
|
template<class VOICE, class VIDEO>
|
||||||
|
class CompositeMediaEngine : public MediaEngine {
|
||||||
|
public:
|
||||||
|
CompositeMediaEngine() {}
|
||||||
|
virtual ~CompositeMediaEngine() {}
|
||||||
|
virtual bool Init() {
|
||||||
|
if (!voice_.Init())
|
||||||
|
return false;
|
||||||
|
if (!video_.Init()) {
|
||||||
|
voice_.Terminate();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
SignalVideoCaptureResult.repeat(video_.SignalCaptureResult);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
virtual void Terminate() {
|
||||||
|
video_.Terminate();
|
||||||
|
voice_.Terminate();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual int GetCapabilities() {
|
||||||
|
return (voice_.GetCapabilities() | video_.GetCapabilities());
|
||||||
|
}
|
||||||
|
virtual VoiceMediaChannel *CreateChannel() {
|
||||||
|
return voice_.CreateChannel();
|
||||||
|
}
|
||||||
|
virtual VideoMediaChannel *CreateVideoChannel(VoiceMediaChannel* channel) {
|
||||||
|
return video_.CreateChannel(channel);
|
||||||
|
}
|
||||||
|
virtual SoundclipMedia *CreateSoundclip() {
|
||||||
|
return voice_.CreateSoundclip();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool SetAudioOptions(int o) {
|
||||||
|
return voice_.SetOptions(o);
|
||||||
|
}
|
||||||
|
virtual bool SetVideoOptions(int o) {
|
||||||
|
return video_.SetOptions(o);
|
||||||
|
}
|
||||||
|
virtual bool SetDefaultVideoEncoderConfig(const VideoEncoderConfig& config) {
|
||||||
|
return video_.SetDefaultEncoderConfig(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool SetSoundDevices(const Device* in_device,
|
||||||
|
const Device* out_device) {
|
||||||
|
return voice_.SetDevices(in_device, out_device);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool SetVideoCaptureDevice(const Device* cam_device) {
|
||||||
|
return video_.SetCaptureDevice(cam_device);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool SetVideoRenderer(int channel_id,
|
||||||
|
void* window,
|
||||||
|
unsigned int zOrder,
|
||||||
|
float left,
|
||||||
|
float top,
|
||||||
|
float right,
|
||||||
|
float bottom) {
|
||||||
|
return video_.SetVideoRenderer(channel_id,
|
||||||
|
window,
|
||||||
|
zOrder,
|
||||||
|
left,
|
||||||
|
top,
|
||||||
|
right,
|
||||||
|
bottom);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool GetOutputVolume(int* level) {
|
||||||
|
return voice_.GetOutputVolume(level);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool SetOutputVolume(int level) {
|
||||||
|
return voice_.SetOutputVolume(level);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual int GetInputLevel() {
|
||||||
|
return voice_.GetInputLevel();
|
||||||
|
}
|
||||||
|
virtual bool SetLocalMonitor(bool enable) {
|
||||||
|
return voice_.SetLocalMonitor(enable);
|
||||||
|
}
|
||||||
|
virtual bool SetLocalRenderer(VideoRenderer* renderer) {
|
||||||
|
return video_.SetLocalRenderer(renderer);
|
||||||
|
}
|
||||||
|
virtual CaptureResult SetVideoCapture(bool capture) {
|
||||||
|
return video_.SetCapture(capture);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual const std::vector<AudioCodec>& audio_codecs() {
|
||||||
|
return voice_.codecs();
|
||||||
|
}
|
||||||
|
virtual const std::vector<VideoCodec>& video_codecs() {
|
||||||
|
return video_.codecs();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void SetVoiceLogging(int min_sev, const char* filter) {
|
||||||
|
return voice_.SetLogging(min_sev, filter);
|
||||||
|
}
|
||||||
|
virtual void SetVideoLogging(int min_sev, const char* filter) {
|
||||||
|
return video_.SetLogging(min_sev, filter);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
VOICE voice_;
|
||||||
|
VIDEO video_;
|
||||||
|
};
|
||||||
|
|
||||||
|
// NullVoiceEngine can be used with CompositeMediaEngine in the case where only
|
||||||
|
// a video engine is desired.
|
||||||
|
class NullVoiceEngine {
|
||||||
|
public:
|
||||||
|
bool Init() { return true; }
|
||||||
|
void Terminate() {}
|
||||||
|
int GetCapabilities() { return 0; }
|
||||||
|
// If you need this to return an actual channel, use FakeMediaEngine instead.
|
||||||
|
VoiceMediaChannel* CreateChannel() {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
SoundclipMedia* CreateSoundclip() {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
bool SetOptions(int opts) { return true; }
|
||||||
|
bool SetDevices(const Device* in_device, const Device* out_device) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool GetOutputVolume(int* level) { *level = 0; return true; }
|
||||||
|
bool SetOutputVolume(int level) { return true; }
|
||||||
|
int GetInputLevel() { return 0; }
|
||||||
|
bool SetLocalMonitor(bool enable) { return true; }
|
||||||
|
const std::vector<AudioCodec>& codecs() { return codecs_; }
|
||||||
|
void SetLogging(int min_sev, const char* filter) {}
|
||||||
|
private:
|
||||||
|
std::vector<AudioCodec> codecs_;
|
||||||
|
};
|
||||||
|
|
||||||
|
// NullVideoEngine can be used with CompositeMediaEngine in the case where only
|
||||||
|
// a voice engine is desired.
|
||||||
|
class NullVideoEngine {
|
||||||
|
public:
|
||||||
|
bool Init() { return true; }
|
||||||
|
void Terminate() {}
|
||||||
|
int GetCapabilities() { return 0; }
|
||||||
|
// If you need this to return an actual channel, use FakeMediaEngine instead.
|
||||||
|
VideoMediaChannel* CreateChannel(
|
||||||
|
VoiceMediaChannel* voice_media_channel) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
bool SetOptions(int opts) { return true; }
|
||||||
|
bool SetDefaultEncoderConfig(const VideoEncoderConfig& config) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool SetCaptureDevice(const Device* cam_device) { return true; }
|
||||||
|
bool SetLocalRenderer(VideoRenderer* renderer) { return true; }
|
||||||
|
CaptureResult SetCapture(bool capture) { return CR_SUCCESS; }
|
||||||
|
const std::vector<VideoCodec>& codecs() { return codecs_; }
|
||||||
|
void SetLogging(int min_sev, const char* filter) {}
|
||||||
|
sigslot::signal1<CaptureResult> SignalCaptureResult;
|
||||||
|
private:
|
||||||
|
std::vector<VideoCodec> codecs_;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef CompositeMediaEngine<NullVoiceEngine, NullVideoEngine> NullMediaEngine;
|
||||||
|
|
||||||
|
} // namespace cricket
|
||||||
|
|
||||||
|
#endif // TALK_SESSION_PHONE_MEDIAENGINE_H_
|
||||||
@ -0,0 +1,242 @@
|
|||||||
|
/*
|
||||||
|
* 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 "talk/session/phone/mediamessages.h"
|
||||||
|
|
||||||
|
#include "talk/base/stringencode.h"
|
||||||
|
#include "talk/p2p/base/constants.h"
|
||||||
|
#include "talk/session/phone/mediasessionclient.h"
|
||||||
|
#include "talk/xmllite/xmlelement.h"
|
||||||
|
|
||||||
|
namespace cricket {
|
||||||
|
|
||||||
|
const NamedSource* GetFirstSourceByNick(const NamedSources& sources,
|
||||||
|
const std::string& nick) {
|
||||||
|
for (NamedSources::const_iterator source = sources.begin();
|
||||||
|
source != sources.end(); ++source) {
|
||||||
|
if (source->nick == nick) {
|
||||||
|
return &*source;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
const NamedSource* GetSourceBySsrc(const NamedSources& sources, uint32 ssrc) {
|
||||||
|
for (NamedSources::const_iterator source = sources.begin();
|
||||||
|
source != sources.end(); ++source) {
|
||||||
|
if (source->ssrc == ssrc) {
|
||||||
|
return &*source;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
const NamedSource* MediaSources::GetFirstAudioSourceByNick(
|
||||||
|
const std::string& nick) {
|
||||||
|
return GetFirstSourceByNick(audio, nick);
|
||||||
|
}
|
||||||
|
|
||||||
|
const NamedSource* MediaSources::GetFirstVideoSourceByNick(
|
||||||
|
const std::string& nick) {
|
||||||
|
return GetFirstSourceByNick(video, nick);
|
||||||
|
}
|
||||||
|
|
||||||
|
const NamedSource* MediaSources::GetAudioSourceBySsrc(uint32 ssrc) {
|
||||||
|
return GetSourceBySsrc(audio, ssrc);
|
||||||
|
}
|
||||||
|
|
||||||
|
const NamedSource* MediaSources::GetVideoSourceBySsrc(uint32 ssrc) {
|
||||||
|
return GetSourceBySsrc(video, ssrc);
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: There is no check here for duplicate sources, so check before
|
||||||
|
// adding.
|
||||||
|
void AddSource(NamedSources* sources, const NamedSource& source) {
|
||||||
|
sources->push_back(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MediaSources::AddAudioSource(const NamedSource& source) {
|
||||||
|
AddSource(&audio, source);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MediaSources::AddVideoSource(const NamedSource& source) {
|
||||||
|
AddSource(&video, source);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RemoveSourceBySsrc(NamedSources* sources, uint32 ssrc) {
|
||||||
|
for (NamedSources::iterator source = sources->begin();
|
||||||
|
source != sources->end(); ) {
|
||||||
|
if (source->ssrc == ssrc) {
|
||||||
|
source = sources->erase(source);
|
||||||
|
} else {
|
||||||
|
++source;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MediaSources::RemoveAudioSourceBySsrc(uint32 ssrc) {
|
||||||
|
RemoveSourceBySsrc(&audio, ssrc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MediaSources::RemoveVideoSourceBySsrc(uint32 ssrc) {
|
||||||
|
RemoveSourceBySsrc(&video, ssrc);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ParseSsrc(const std::string& string, uint32* ssrc) {
|
||||||
|
return talk_base::FromString(string, ssrc);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ParseSsrc(const buzz::XmlElement* element, uint32* ssrc) {
|
||||||
|
if (element == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return ParseSsrc(element->BodyText(), ssrc);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ParseNamedSource(const buzz::XmlElement* source_elem,
|
||||||
|
NamedSource* named_source,
|
||||||
|
ParseError* error) {
|
||||||
|
named_source->nick = source_elem->Attr(QN_JINGLE_DRAFT_SOURCE_NICK);
|
||||||
|
if (named_source->nick.empty()) {
|
||||||
|
return BadParse("Missing or invalid nick.", error);
|
||||||
|
}
|
||||||
|
|
||||||
|
named_source->name = source_elem->Attr(QN_JINGLE_DRAFT_SOURCE_NAME);
|
||||||
|
named_source->usage = source_elem->Attr(QN_JINGLE_DRAFT_SOURCE_USAGE);
|
||||||
|
named_source->removed =
|
||||||
|
(STR_JINGLE_DRAFT_SOURCE_STATE_REMOVED ==
|
||||||
|
source_elem->Attr(QN_JINGLE_DRAFT_SOURCE_STATE));
|
||||||
|
|
||||||
|
const buzz::XmlElement* ssrc_elem =
|
||||||
|
source_elem->FirstNamed(QN_JINGLE_DRAFT_SOURCE_SSRC);
|
||||||
|
if (ssrc_elem != NULL && !ssrc_elem->BodyText().empty()) {
|
||||||
|
uint32 ssrc;
|
||||||
|
if (!ParseSsrc(ssrc_elem->BodyText(), &ssrc)) {
|
||||||
|
return BadParse("Missing or invalid ssrc.", error);
|
||||||
|
}
|
||||||
|
named_source->SetSsrc(ssrc);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsSourcesNotify(const buzz::XmlElement* action_elem) {
|
||||||
|
return action_elem->FirstNamed(QN_JINGLE_DRAFT_NOTIFY) != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ParseSourcesNotify(const buzz::XmlElement* action_elem,
|
||||||
|
const SessionDescription* session_description,
|
||||||
|
MediaSources* sources,
|
||||||
|
ParseError* error) {
|
||||||
|
for (const buzz::XmlElement* notify_elem
|
||||||
|
= action_elem->FirstNamed(QN_JINGLE_DRAFT_NOTIFY);
|
||||||
|
notify_elem != NULL;
|
||||||
|
notify_elem = notify_elem->NextNamed(QN_JINGLE_DRAFT_NOTIFY)) {
|
||||||
|
std::string content_name = notify_elem->Attr(QN_JINGLE_DRAFT_CONTENT_NAME);
|
||||||
|
for (const buzz::XmlElement* source_elem
|
||||||
|
= notify_elem->FirstNamed(QN_JINGLE_DRAFT_SOURCE);
|
||||||
|
source_elem != NULL;
|
||||||
|
source_elem = source_elem->NextNamed(QN_JINGLE_DRAFT_SOURCE)) {
|
||||||
|
NamedSource named_source;
|
||||||
|
if (!ParseNamedSource(source_elem, &named_source, error)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (session_description == NULL) {
|
||||||
|
return BadParse("unknown content name: " + content_name, error);
|
||||||
|
}
|
||||||
|
const ContentInfo* content =
|
||||||
|
FindContentInfoByName(session_description->contents(), content_name);
|
||||||
|
if (content == NULL) {
|
||||||
|
return BadParse("unknown content name: " + content_name, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsAudioContent(content)) {
|
||||||
|
sources->audio.push_back(named_source);
|
||||||
|
} else if (IsVideoContent(content)) {
|
||||||
|
sources->video.push_back(named_source);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
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_JINGLE_DRAFT_CONTENT_NAME, name);
|
||||||
|
view_elem->SetAttr(QN_JINGLE_DRAFT_VIEW_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_JINGLE_DRAFT_VIEW_SSRC, view.ssrc);
|
||||||
|
|
||||||
|
buzz::XmlElement* params_elem = new buzz::XmlElement(
|
||||||
|
QN_JINGLE_DRAFT_VIEW_PARAMS);
|
||||||
|
AddXmlAttr(params_elem, QN_JINGLE_DRAFT_VIEW_PARAMS_WIDTH, view.width);
|
||||||
|
AddXmlAttr(params_elem, QN_JINGLE_DRAFT_VIEW_PARAMS_HEIGHT, view.height);
|
||||||
|
AddXmlAttr(params_elem, QN_JINGLE_DRAFT_VIEW_PARAMS_FRAMERATE,
|
||||||
|
view.framerate);
|
||||||
|
AddXmlAttr(params_elem, QN_JINGLE_DRAFT_VIEW_PARAMS_PREFERENCE,
|
||||||
|
view.preference);
|
||||||
|
view_elem->AddElement(params_elem);
|
||||||
|
|
||||||
|
return view_elem;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WriteViewRequest(const std::string& content_name,
|
||||||
|
const ViewRequest& request,
|
||||||
|
XmlElements* elems,
|
||||||
|
WriteError* error) {
|
||||||
|
if (request.static_video_views.size() == 0) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace cricket
|
||||||
@ -0,0 +1,106 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TALK_SESSION_PHONE_MEDIAMESSAGES_H_
|
||||||
|
#define TALK_SESSION_PHONE_MEDIAMESSAGES_H_
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include "talk/base/basictypes.h"
|
||||||
|
#include "talk/p2p/base/parsing.h"
|
||||||
|
#include "talk/p2p/base/sessiondescription.h"
|
||||||
|
|
||||||
|
namespace cricket {
|
||||||
|
|
||||||
|
struct NamedSource {
|
||||||
|
NamedSource() : ssrc(0), ssrc_set(false), removed(false) {}
|
||||||
|
|
||||||
|
void SetSsrc(uint32 ssrc) {
|
||||||
|
this->ssrc = ssrc;
|
||||||
|
this->ssrc_set = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string nick;
|
||||||
|
std::string name;
|
||||||
|
std::string usage;
|
||||||
|
uint32 ssrc;
|
||||||
|
bool ssrc_set;
|
||||||
|
bool removed;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::vector<NamedSource> NamedSources;
|
||||||
|
|
||||||
|
class MediaSources {
|
||||||
|
public:
|
||||||
|
const NamedSource* GetAudioSourceBySsrc(uint32 ssrc);
|
||||||
|
const NamedSource* GetVideoSourceBySsrc(uint32 ssrc);
|
||||||
|
// TODO: Remove once all senders use excplict remove by ssrc.
|
||||||
|
const NamedSource* GetFirstAudioSourceByNick(const std::string& nick);
|
||||||
|
const NamedSource* GetFirstVideoSourceByNick(const std::string& nick);
|
||||||
|
void AddAudioSource(const NamedSource& source);
|
||||||
|
void AddVideoSource(const NamedSource& source);
|
||||||
|
void RemoveAudioSourceBySsrc(uint32 ssrc);
|
||||||
|
void RemoveVideoSourceBySsrc(uint32 ssrc);
|
||||||
|
NamedSources audio;
|
||||||
|
NamedSources video;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct StaticVideoView {
|
||||||
|
StaticVideoView(uint32 ssrc, int width, int height, int framerate)
|
||||||
|
: ssrc(ssrc),
|
||||||
|
width(width),
|
||||||
|
height(height),
|
||||||
|
framerate(framerate),
|
||||||
|
preference(0) {}
|
||||||
|
|
||||||
|
uint32 ssrc;
|
||||||
|
int width;
|
||||||
|
int height;
|
||||||
|
int framerate;
|
||||||
|
int preference;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::vector<StaticVideoView> StaticVideoViews;
|
||||||
|
|
||||||
|
struct ViewRequest {
|
||||||
|
StaticVideoViews static_video_views;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool WriteViewRequest(const std::string& content_name,
|
||||||
|
const ViewRequest& view,
|
||||||
|
XmlElements* elems,
|
||||||
|
WriteError* error);
|
||||||
|
|
||||||
|
bool IsSourcesNotify(const buzz::XmlElement* action_elem);
|
||||||
|
// The session_description is needed to map content_name => media type.
|
||||||
|
bool ParseSourcesNotify(const buzz::XmlElement* action_elem,
|
||||||
|
const SessionDescription* session_description,
|
||||||
|
MediaSources* sources,
|
||||||
|
ParseError* error);
|
||||||
|
} // namespace cricket
|
||||||
|
|
||||||
|
#endif // TALK_SESSION_PHONE_MEDIAMESSAGES_H_
|
||||||
@ -0,0 +1,289 @@
|
|||||||
|
/*
|
||||||
|
* 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 TALK_SESSION_PHONE_MEDIASESSIONCLIENT_H_
|
||||||
|
#define TALK_SESSION_PHONE_MEDIASESSIONCLIENT_H_
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <map>
|
||||||
|
#include <algorithm>
|
||||||
|
#include "talk/session/phone/call.h"
|
||||||
|
#include "talk/session/phone/channelmanager.h"
|
||||||
|
#include "talk/session/phone/cryptoparams.h"
|
||||||
|
#include "talk/base/sigslot.h"
|
||||||
|
#include "talk/base/sigslotrepeater.h"
|
||||||
|
#include "talk/base/messagequeue.h"
|
||||||
|
#include "talk/base/thread.h"
|
||||||
|
#include "talk/p2p/base/sessionmanager.h"
|
||||||
|
#include "talk/p2p/base/session.h"
|
||||||
|
#include "talk/p2p/base/sessionclient.h"
|
||||||
|
#include "talk/p2p/base/sessiondescription.h"
|
||||||
|
|
||||||
|
namespace cricket {
|
||||||
|
|
||||||
|
class Call;
|
||||||
|
class SessionDescription;
|
||||||
|
typedef std::vector<AudioCodec> AudioCodecs;
|
||||||
|
typedef std::vector<VideoCodec> VideoCodecs;
|
||||||
|
|
||||||
|
// SEC_ENABLED and SEC_REQUIRED should only be used if the session
|
||||||
|
// was negotiated over TLS, to protect the inline crypto material
|
||||||
|
// exchange.
|
||||||
|
// SEC_DISABLED: No crypto in outgoing offer and answer. Fail any
|
||||||
|
// offer with crypto required.
|
||||||
|
// SEC_ENABLED: Crypto in outgoing offer and answer. Fail any offer
|
||||||
|
// with unsupported required crypto. Crypto set but not
|
||||||
|
// required in outgoing offer.
|
||||||
|
// SEC_REQUIRED: Crypto in outgoing offer and answer with
|
||||||
|
// required='true'. Fail any offer with no or
|
||||||
|
// unsupported crypto (implicit crypto required='true'
|
||||||
|
// in the offer.)
|
||||||
|
enum SecureMediaPolicy {SEC_DISABLED, SEC_ENABLED, SEC_REQUIRED};
|
||||||
|
|
||||||
|
const int kAutoBandwidth = -1;
|
||||||
|
|
||||||
|
struct CallOptions {
|
||||||
|
CallOptions() :
|
||||||
|
is_video(false),
|
||||||
|
is_muc(false),
|
||||||
|
video_bandwidth(kAutoBandwidth) {
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_video;
|
||||||
|
bool is_muc;
|
||||||
|
// bps. -1 == auto.
|
||||||
|
int video_bandwidth;
|
||||||
|
};
|
||||||
|
|
||||||
|
class MediaSessionClient: public SessionClient, public sigslot::has_slots<> {
|
||||||
|
public:
|
||||||
|
|
||||||
|
MediaSessionClient(const buzz::Jid& jid, SessionManager *manager);
|
||||||
|
// Alternative constructor, allowing injection of media_engine
|
||||||
|
// and device_manager.
|
||||||
|
MediaSessionClient(const buzz::Jid& jid, SessionManager *manager,
|
||||||
|
MediaEngine* media_engine, DeviceManager* device_manager);
|
||||||
|
~MediaSessionClient();
|
||||||
|
|
||||||
|
const buzz::Jid &jid() const { return jid_; }
|
||||||
|
SessionManager* session_manager() const { return session_manager_; }
|
||||||
|
ChannelManager* channel_manager() const { return channel_manager_; }
|
||||||
|
|
||||||
|
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<std::string>* names) {
|
||||||
|
return channel_manager_->GetAudioInputDevices(names);
|
||||||
|
}
|
||||||
|
bool GetAudioOutputDevices(std::vector<std::string>* names) {
|
||||||
|
return channel_manager_->GetAudioOutputDevices(names);
|
||||||
|
}
|
||||||
|
bool GetVideoCaptureDevices(std::vector<std::string>* names) {
|
||||||
|
return channel_manager_->GetVideoCaptureDevices(names);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SetAudioOptions(const std::string& in_name, const std::string& out_name,
|
||||||
|
int opts) {
|
||||||
|
return channel_manager_->SetAudioOptions(in_name, out_name, opts);
|
||||||
|
}
|
||||||
|
bool SetOutputVolume(int level) {
|
||||||
|
return channel_manager_->SetOutputVolume(level);
|
||||||
|
}
|
||||||
|
bool SetVideoOptions(const std::string& cam_device) {
|
||||||
|
return channel_manager_->SetVideoOptions(cam_device);
|
||||||
|
}
|
||||||
|
|
||||||
|
sigslot::signal2<Call *, Call *> SignalFocus;
|
||||||
|
sigslot::signal1<Call *> SignalCallCreate;
|
||||||
|
sigslot::signal1<Call *> SignalCallDestroy;
|
||||||
|
sigslot::repeater0<> SignalDevicesChange;
|
||||||
|
|
||||||
|
SessionDescription* CreateOffer(const CallOptions& options);
|
||||||
|
SessionDescription* CreateAnswer(const SessionDescription* offer,
|
||||||
|
const CallOptions& options);
|
||||||
|
|
||||||
|
SecureMediaPolicy secure() const { return secure_; }
|
||||||
|
void set_secure(SecureMediaPolicy s) { secure_ = s; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
void Construct();
|
||||||
|
void OnSessionCreate(Session *session, bool received_initiate);
|
||||||
|
void OnSessionState(BaseSession *session, BaseSession::State state);
|
||||||
|
void OnSessionDestroy(Session *session);
|
||||||
|
virtual bool ParseContent(SignalingProtocol protocol,
|
||||||
|
const buzz::XmlElement* elem,
|
||||||
|
const ContentDescription** content,
|
||||||
|
ParseError* error);
|
||||||
|
virtual bool WriteContent(SignalingProtocol protocol,
|
||||||
|
const ContentDescription* content,
|
||||||
|
buzz::XmlElement** elem,
|
||||||
|
WriteError* error);
|
||||||
|
Session *CreateSession(Call *call);
|
||||||
|
|
||||||
|
buzz::Jid jid_;
|
||||||
|
SessionManager* session_manager_;
|
||||||
|
Call *focus_call_;
|
||||||
|
ChannelManager *channel_manager_;
|
||||||
|
std::map<uint32, Call *> calls_;
|
||||||
|
std::map<std::string, Call *> session_map_;
|
||||||
|
SecureMediaPolicy secure_;
|
||||||
|
friend class Call;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum MediaType {
|
||||||
|
MEDIA_TYPE_AUDIO,
|
||||||
|
MEDIA_TYPE_VIDEO
|
||||||
|
};
|
||||||
|
|
||||||
|
class MediaContentDescription : public ContentDescription {
|
||||||
|
public:
|
||||||
|
MediaContentDescription()
|
||||||
|
: ssrc_(0),
|
||||||
|
ssrc_set_(false),
|
||||||
|
rtcp_mux_(false),
|
||||||
|
bandwidth_(kAutoBandwidth),
|
||||||
|
crypto_required_(false),
|
||||||
|
rtp_header_extensions_set_(false) {
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual MediaType type() const = 0;
|
||||||
|
|
||||||
|
uint32 ssrc() const { return ssrc_; }
|
||||||
|
bool ssrc_set() const { return ssrc_set_; }
|
||||||
|
void set_ssrc(uint32 ssrc) {
|
||||||
|
ssrc_ = ssrc;
|
||||||
|
ssrc_set_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool rtcp_mux() const { return rtcp_mux_; }
|
||||||
|
void set_rtcp_mux(bool mux) { rtcp_mux_ = mux; }
|
||||||
|
|
||||||
|
int bandwidth() const { return bandwidth_; }
|
||||||
|
void set_bandwidth(int bandwidth) { bandwidth_ = bandwidth; }
|
||||||
|
|
||||||
|
const std::vector<CryptoParams>& cryptos() const { return cryptos_; }
|
||||||
|
void AddCrypto(const CryptoParams& params) {
|
||||||
|
cryptos_.push_back(params);
|
||||||
|
}
|
||||||
|
bool crypto_required() const { return crypto_required_; }
|
||||||
|
void set_crypto_required(bool crypto) {
|
||||||
|
crypto_required_ = crypto;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<RtpHeaderExtension>& rtp_header_extensions() const {
|
||||||
|
return rtp_header_extensions_;
|
||||||
|
}
|
||||||
|
void AddRtpHeaderExtension(const RtpHeaderExtension& ext) {
|
||||||
|
rtp_header_extensions_.push_back(ext);
|
||||||
|
rtp_header_extensions_set_ = true;
|
||||||
|
}
|
||||||
|
void ClearRtpHeaderExtensions() {
|
||||||
|
rtp_header_extensions_.clear();
|
||||||
|
rtp_header_extensions_set_ = true;
|
||||||
|
}
|
||||||
|
// We can't always tell if an empty list of header extensions is
|
||||||
|
// because the other side doesn't support them, or just isn't hooked up to
|
||||||
|
// signal them. For now we assume an empty list means no signaling, but
|
||||||
|
// provide the ClearRtpHeaderExtensions method to allow "no support" to be
|
||||||
|
// clearly indicated (i.e. when derived from other information).
|
||||||
|
bool rtp_header_extensions_set() const {
|
||||||
|
return rtp_header_extensions_set_;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
uint32 ssrc_;
|
||||||
|
bool ssrc_set_;
|
||||||
|
bool rtcp_mux_;
|
||||||
|
int bandwidth_;
|
||||||
|
std::vector<CryptoParams> cryptos_;
|
||||||
|
bool crypto_required_;
|
||||||
|
std::vector<RtpHeaderExtension> rtp_header_extensions_;
|
||||||
|
bool rtp_header_extensions_set_;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class C>
|
||||||
|
class MediaContentDescriptionImpl : public MediaContentDescription {
|
||||||
|
public:
|
||||||
|
struct PreferenceSort {
|
||||||
|
bool operator()(C a, C b) { return a.preference > b.preference; }
|
||||||
|
};
|
||||||
|
|
||||||
|
const std::vector<C>& codecs() const { return codecs_; }
|
||||||
|
void AddCodec(const C& codec) {
|
||||||
|
codecs_.push_back(codec);
|
||||||
|
}
|
||||||
|
void SortCodecs() {
|
||||||
|
std::sort(codecs_.begin(), codecs_.end(), PreferenceSort());
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<C> codecs_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class AudioContentDescription : public MediaContentDescriptionImpl<AudioCodec> {
|
||||||
|
public:
|
||||||
|
AudioContentDescription() :
|
||||||
|
conference_mode_(false) {}
|
||||||
|
|
||||||
|
virtual MediaType type() const { return MEDIA_TYPE_AUDIO; }
|
||||||
|
|
||||||
|
bool conference_mode() const { return conference_mode_; }
|
||||||
|
void set_conference_mode(bool enable) {
|
||||||
|
conference_mode_ = enable;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string &lang() const { return lang_; }
|
||||||
|
void set_lang(const std::string &lang) { lang_ = lang; }
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool conference_mode_;
|
||||||
|
std::string lang_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class VideoContentDescription : public MediaContentDescriptionImpl<VideoCodec> {
|
||||||
|
public:
|
||||||
|
virtual MediaType type() const { return MEDIA_TYPE_VIDEO; }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Convenience functions.
|
||||||
|
bool IsAudioContent(const ContentInfo* content);
|
||||||
|
bool IsVideoContent(const ContentInfo* content);
|
||||||
|
const ContentInfo* GetFirstAudioContent(const SessionDescription* sdesc);
|
||||||
|
const ContentInfo* GetFirstVideoContent(const SessionDescription* sdesc);
|
||||||
|
|
||||||
|
} // namespace cricket
|
||||||
|
|
||||||
|
#endif // TALK_SESSION_PHONE_MEDIASESSIONCLIENT_H_
|
||||||
254
third_party_mods/libvpx/libvpx.gyp
Normal file
254
third_party_mods/libvpx/libvpx.gyp
Normal file
@ -0,0 +1,254 @@
|
|||||||
|
# Copyright (c) 2010 The Chromium Authors. All rights reserved.
|
||||||
|
# Use of this source code is governed by a BSD-style license that can be
|
||||||
|
# found in the LICENSE file.
|
||||||
|
{
|
||||||
|
'targets': [
|
||||||
|
{
|
||||||
|
'target_name': 'libvpx',
|
||||||
|
'type': 'static_library',
|
||||||
|
# Don't build yasm from source on Windows
|
||||||
|
'conditions': [
|
||||||
|
['OS!="win"', {
|
||||||
|
'dependencies': [
|
||||||
|
'../yasm/yasm.gyp:yasm#host',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'variables': {
|
||||||
|
'shared_generated_dir':
|
||||||
|
'<(SHARED_INTERMEDIATE_DIR)/third_party/libvpx',
|
||||||
|
'yasm_path': '<(PRODUCT_DIR)/yasm',
|
||||||
|
'yasm_flags': [
|
||||||
|
'-I', 'config/<(OS)/<(target_arch)',
|
||||||
|
'-I', '.'
|
||||||
|
],
|
||||||
|
'conditions': [
|
||||||
|
['OS!="win"', {
|
||||||
|
'asm_obj_dir':
|
||||||
|
'<(shared_generated_dir)',
|
||||||
|
'obj_file_ending':
|
||||||
|
'o',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'asm_obj_dir':
|
||||||
|
'asm',
|
||||||
|
'obj_file_ending':
|
||||||
|
'obj',
|
||||||
|
'yasm_path': '../yasm/binaries/win/yasm.exe',
|
||||||
|
}
|
||||||
|
],
|
||||||
|
['target_arch=="ia32"', {
|
||||||
|
'conditions': [
|
||||||
|
['OS=="linux"', {
|
||||||
|
'yasm_flags': [
|
||||||
|
'-felf32',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
['OS=="mac"', {
|
||||||
|
'yasm_flags': [
|
||||||
|
'-fmacho32',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
['OS=="win"', {
|
||||||
|
'yasm_flags': [
|
||||||
|
'-fwin32',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'yasm_flags': [
|
||||||
|
'-m', 'x86',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
['target_arch=="x64"', {
|
||||||
|
'conditions': [
|
||||||
|
['OS=="linux"', {
|
||||||
|
'yasm_flags': [
|
||||||
|
'-felf64',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
['OS=="mac"', {
|
||||||
|
'yasm_flags': [
|
||||||
|
'-fmacho64',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
['OS=="win"', {
|
||||||
|
'yasm_flags': [
|
||||||
|
'-win64',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'yasm_flags': [
|
||||||
|
'-m', 'amd64',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
'include_dirs': [
|
||||||
|
'config/<(OS)/<(target_arch)',
|
||||||
|
'build',
|
||||||
|
'.',
|
||||||
|
'vp8/common',
|
||||||
|
'vp8/decoder',
|
||||||
|
'vp8/encoder',
|
||||||
|
],
|
||||||
|
'rules': [
|
||||||
|
{
|
||||||
|
'rule_name': 'assemble',
|
||||||
|
'extension': 'asm',
|
||||||
|
'inputs': [ '<(yasm_path)', ],
|
||||||
|
'outputs': [
|
||||||
|
'<(asm_obj_dir)/<(RULE_INPUT_ROOT).<(obj_file_ending)',
|
||||||
|
],
|
||||||
|
'action': [
|
||||||
|
'<(yasm_path)',
|
||||||
|
'<@(yasm_flags)',
|
||||||
|
'-o', '<(asm_obj_dir)/<(RULE_INPUT_ROOT).<(obj_file_ending)',
|
||||||
|
'<(RULE_INPUT_PATH)',
|
||||||
|
],
|
||||||
|
'process_outputs_as_sources': 1,
|
||||||
|
'message': 'Build libvpx yasm build <(RULE_INPUT_PATH).',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
'sources': [
|
||||||
|
'vpx/src/vpx_decoder.c',
|
||||||
|
'vpx/src/vpx_decoder_compat.c',
|
||||||
|
'vpx/src/vpx_encoder.c',
|
||||||
|
'vpx/src/vpx_codec.c',
|
||||||
|
'vpx/src/vpx_image.c',
|
||||||
|
'vpx_mem/vpx_mem.c',
|
||||||
|
'vpx_scale/generic/vpxscale.c',
|
||||||
|
'vpx_scale/generic/yv12config.c',
|
||||||
|
'vpx_scale/generic/yv12extend.c',
|
||||||
|
'vpx_scale/generic/scalesystemdependant.c',
|
||||||
|
'vpx_scale/generic/gen_scalers.c',
|
||||||
|
'vp8/common/alloccommon.c',
|
||||||
|
'vp8/common/blockd.c',
|
||||||
|
'vp8/common/debugmodes.c',
|
||||||
|
'vp8/common/entropy.c',
|
||||||
|
'vp8/common/entropymode.c',
|
||||||
|
'vp8/common/entropymv.c',
|
||||||
|
'vp8/common/extend.c',
|
||||||
|
'vp8/common/filter.c',
|
||||||
|
'vp8/common/findnearmv.c',
|
||||||
|
'vp8/common/generic/systemdependent.c',
|
||||||
|
'vp8/common/idctllm.c',
|
||||||
|
'vp8/common/invtrans.c',
|
||||||
|
'vp8/common/loopfilter.c',
|
||||||
|
'vp8/common/loopfilter_filters.c',
|
||||||
|
'vp8/common/mbpitch.c',
|
||||||
|
'vp8/common/modecont.c',
|
||||||
|
'vp8/common/modecontext.c',
|
||||||
|
'vp8/common/postproc.c',
|
||||||
|
'vp8/common/quant_common.c',
|
||||||
|
'vp8/common/recon.c',
|
||||||
|
'vp8/common/reconinter.c',
|
||||||
|
'vp8/common/reconintra.c',
|
||||||
|
'vp8/common/reconintra4x4.c',
|
||||||
|
'vp8/common/setupintrarecon.c',
|
||||||
|
'vp8/common/swapyv12buffer.c',
|
||||||
|
'vp8/common/textblit.c',
|
||||||
|
'vp8/common/treecoder.c',
|
||||||
|
'vp8/common/x86/x86_systemdependent.c',
|
||||||
|
'vp8/common/x86/vp8_asm_stubs.c',
|
||||||
|
'vp8/common/x86/loopfilter_x86.c',
|
||||||
|
'vp8/vp8_cx_iface.c',
|
||||||
|
'vp8/encoder/bitstream.c',
|
||||||
|
'vp8/encoder/boolhuff.c',
|
||||||
|
'vp8/encoder/dct.c',
|
||||||
|
'vp8/encoder/encodeframe.c',
|
||||||
|
'vp8/encoder/encodeintra.c',
|
||||||
|
'vp8/encoder/encodemb.c',
|
||||||
|
'vp8/encoder/encodemv.c',
|
||||||
|
'vp8/encoder/ethreading.c',
|
||||||
|
'vp8/encoder/firstpass.c',
|
||||||
|
'vp8/encoder/generic/csystemdependent.c',
|
||||||
|
'vp8/encoder/mcomp.c',
|
||||||
|
'vp8/encoder/modecosts.c',
|
||||||
|
'vp8/encoder/onyx_if.c',
|
||||||
|
'vp8/encoder/pickinter.c',
|
||||||
|
'vp8/encoder/picklpf.c',
|
||||||
|
'vp8/encoder/psnr.c',
|
||||||
|
'vp8/encoder/quantize.c',
|
||||||
|
'vp8/encoder/ratectrl.c',
|
||||||
|
'vp8/encoder/rdopt.c',
|
||||||
|
'vp8/encoder/sad_c.c',
|
||||||
|
'vp8/encoder/segmentation.c',
|
||||||
|
'vp8/encoder/tokenize.c',
|
||||||
|
'vp8/encoder/treewriter.c',
|
||||||
|
'vp8/encoder/variance_c.c',
|
||||||
|
'vp8/encoder/temporal_filter.c',
|
||||||
|
'vp8/encoder/x86/x86_csystemdependent.c',
|
||||||
|
'vp8/encoder/x86/variance_mmx.c',
|
||||||
|
'vp8/encoder/x86/variance_sse2.c',
|
||||||
|
'vp8/vp8_dx_iface.c',
|
||||||
|
'vp8/decoder/dboolhuff.c',
|
||||||
|
'vp8/decoder/decodemv.c',
|
||||||
|
'vp8/decoder/decodframe.c',
|
||||||
|
'vp8/decoder/dequantize.c',
|
||||||
|
'vp8/decoder/detokenize.c',
|
||||||
|
'vp8/decoder/generic/dsystemdependent.c',
|
||||||
|
'vp8/decoder/onyxd_if.c',
|
||||||
|
'vp8/decoder/threading.c',
|
||||||
|
'vp8/decoder/idct_blk.c',
|
||||||
|
'vp8/decoder/reconintra_mt.c',
|
||||||
|
'vp8/decoder/x86/x86_dsystemdependent.c',
|
||||||
|
'vp8/decoder/x86/idct_blk_mmx.c',
|
||||||
|
'vp8/decoder/x86/idct_blk_sse2.c',
|
||||||
|
'vpx_ports/x86_cpuid.c',
|
||||||
|
# Yasm inputs.
|
||||||
|
'vp8/common/x86/idctllm_mmx.asm',
|
||||||
|
'vp8/common/x86/idctllm_sse2.asm',
|
||||||
|
'vp8/common/x86/iwalsh_mmx.asm',
|
||||||
|
'vp8/common/x86/iwalsh_sse2.asm',
|
||||||
|
'vp8/common/x86/loopfilter_mmx.asm',
|
||||||
|
'vp8/common/x86/loopfilter_sse2.asm',
|
||||||
|
'vp8/common/x86/postproc_mmx.asm',
|
||||||
|
'vp8/common/x86/postproc_sse2.asm',
|
||||||
|
'vp8/common/x86/recon_mmx.asm',
|
||||||
|
'vp8/common/x86/recon_sse2.asm',
|
||||||
|
'vp8/common/x86/subpixel_mmx.asm',
|
||||||
|
'vp8/common/x86/subpixel_sse2.asm',
|
||||||
|
'vp8/common/x86/subpixel_ssse3.asm',
|
||||||
|
'vp8/decoder/x86/dequantize_mmx.asm',
|
||||||
|
'vp8/encoder/x86/dct_mmx.asm',
|
||||||
|
'vp8/encoder/x86/dct_sse2.asm',
|
||||||
|
'vp8/encoder/x86/encodeopt.asm',
|
||||||
|
'vp8/encoder/x86/fwalsh_sse2.asm',
|
||||||
|
'vp8/encoder/x86/quantize_mmx.asm',
|
||||||
|
'vp8/encoder/x86/quantize_sse2.asm',
|
||||||
|
'vp8/encoder/x86/quantize_ssse3.asm',
|
||||||
|
'vp8/encoder/x86/sad_mmx.asm',
|
||||||
|
'vp8/encoder/x86/sad_sse2.asm',
|
||||||
|
'vp8/encoder/x86/sad_sse3.asm',
|
||||||
|
'vp8/encoder/x86/sad_sse4.asm',
|
||||||
|
'vp8/encoder/x86/sad_ssse3.asm',
|
||||||
|
'vp8/encoder/x86/subtract_mmx.asm',
|
||||||
|
'vp8/encoder/x86/subtract_sse2.asm',
|
||||||
|
'vp8/encoder/x86/temporal_filter_apply_sse2.asm',
|
||||||
|
'vp8/encoder/x86/variance_impl_mmx.asm',
|
||||||
|
'vp8/encoder/x86/variance_impl_sse2.asm',
|
||||||
|
'vpx_ports/emms.asm',
|
||||||
|
'vpx_ports/x86_abi_support.asm',
|
||||||
|
|
||||||
|
# Generated by ./configure and checked in.
|
||||||
|
'config/<(OS)/<(target_arch)/vpx_config.c',
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
# Local Variables:
|
||||||
|
# tab-width:2
|
||||||
|
# indent-tabs-mode:nil
|
||||||
|
# End:
|
||||||
|
# vim: set expandtab tabstop=2 shiftwidth=2:
|
||||||
@ -0,0 +1,2 @@
|
|||||||
|
static const char* const cfg = "--target=generic-gnu";
|
||||||
|
const char *vpx_codec_build_config(void) {return cfg;}
|
||||||
83
third_party_mods/libvpx/source/config/android/vpx_config.h
Normal file
83
third_party_mods/libvpx/source/config/android/vpx_config.h
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
/* This file automatically generated by configure. Do not edit! */
|
||||||
|
#define INLINE
|
||||||
|
#define FORCEINLINE
|
||||||
|
#define RESTRICT
|
||||||
|
|
||||||
|
#if defined(__arm__)
|
||||||
|
|
||||||
|
#define ARCH_ARM 1
|
||||||
|
#define HAVE_ARMV5TE 0
|
||||||
|
#else
|
||||||
|
#define ARCH_ARM 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__ARM_HAVE_NEON)
|
||||||
|
#define HAVE_ARMV7 1
|
||||||
|
#else
|
||||||
|
#define HAVE_ARMV7 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__ARM_HAVE_ARMV6)
|
||||||
|
#define HAVE_ARMV6 1
|
||||||
|
#else
|
||||||
|
#define HAVE_ARMV6 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define ARCH_MIPS 0
|
||||||
|
#define ARCH_X86 0
|
||||||
|
#define ARCH_X86_64 0
|
||||||
|
#define ARCH_PPC32 0
|
||||||
|
#define ARCH_PPC64 0
|
||||||
|
|
||||||
|
#define HAVE_IWMMXT 0
|
||||||
|
#define HAVE_IWMMXT2 0
|
||||||
|
#define HAVE_MIPS32 0
|
||||||
|
#define HAVE_MMX 0
|
||||||
|
#define HAVE_SSE 0
|
||||||
|
#define HAVE_SSE2 0
|
||||||
|
#define HAVE_SSE3 0
|
||||||
|
#define HAVE_SSSE3 0
|
||||||
|
#define HAVE_ALTIVEC 0
|
||||||
|
#define HAVE_VPX_PORTS 1
|
||||||
|
#define HAVE_STDINT_H 1
|
||||||
|
#define HAVE_ALT_TREE_LAYOUT 0
|
||||||
|
#define HAVE_PTHREAD_H 1
|
||||||
|
#define HAVE_SYS_MMAN_H 1
|
||||||
|
#define CONFIG_EXTERNAL_BUILD 0
|
||||||
|
#define CONFIG_INSTALL_DOCS 0
|
||||||
|
#define CONFIG_INSTALL_BINS 1
|
||||||
|
#define CONFIG_INSTALL_LIBS 1
|
||||||
|
#define CONFIG_INSTALL_SRCS 1
|
||||||
|
#define CONFIG_DEBUG 0
|
||||||
|
#define CONFIG_GPROF 0
|
||||||
|
#define CONFIG_GCOV 0
|
||||||
|
#define CONFIG_RVCT 0
|
||||||
|
#define CONFIG_GCC 0
|
||||||
|
#define CONFIG_MSVS 0
|
||||||
|
#define CONFIG_PIC 0
|
||||||
|
#define CONFIG_BIG_ENDIAN 0
|
||||||
|
#define CONFIG_CODEC_SRCS 0
|
||||||
|
#define CONFIG_DEBUG_LIBS 0
|
||||||
|
#define CONFIG_FAST_UNALIGNED 1
|
||||||
|
#define CONFIG_MEM_MANAGER 0
|
||||||
|
#define CONFIG_MEM_TRACKER 0
|
||||||
|
#define CONFIG_MEM_CHECKS 0
|
||||||
|
#define CONFIG_MD5 1
|
||||||
|
#define CONFIG_DEQUANT_TOKENS 0
|
||||||
|
#define CONFIG_DC_RECON 0
|
||||||
|
#define CONFIG_NEW_TOKENS 0
|
||||||
|
#define CONFIG_EVAL_LIMIT 0
|
||||||
|
#define CONFIG_RUNTIME_CPU_DETECT 0
|
||||||
|
#define CONFIG_POSTPROC 0
|
||||||
|
#define CONFIG_POSTPROC_GENERIC 0
|
||||||
|
#define CONFIG_OS_SUPPORT 1
|
||||||
|
#define CONFIG_MULTITHREAD 1
|
||||||
|
#define CONFIG_PSNR 0
|
||||||
|
#define CONFIG_VP8_ENCODER 1
|
||||||
|
#define CONFIG_VP8_DECODER 1
|
||||||
|
#define CONFIG_VP8 1
|
||||||
|
#define CONFIG_ENCODERS 1
|
||||||
|
#define CONFIG_DECODERS 1
|
||||||
|
#define CONFIG_STATIC_MSVCRT 0
|
||||||
|
#define CONFIG_SPATIAL_RESAMPLING 1
|
||||||
|
#define CONFIG_REALTIME_ONLY 0
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
#define VERSION_MAJOR 0
|
||||||
|
#define VERSION_MINOR 9
|
||||||
|
#define VERSION_PATCH 6
|
||||||
|
#define VERSION_EXTRA ""
|
||||||
|
#define VERSION_PACKED ((VERSION_MAJOR<<16)|(VERSION_MINOR<<8)|(VERSION_PATCH))
|
||||||
|
#define VERSION_STRING_NOSP "v0.9.6"
|
||||||
|
#define VERSION_STRING " v0.9.6"
|
||||||
@ -0,0 +1,62 @@
|
|||||||
|
ARCH_ARM equ 0
|
||||||
|
ARCH_MIPS equ 0
|
||||||
|
ARCH_X86 equ 1
|
||||||
|
ARCH_X86_64 equ 0
|
||||||
|
ARCH_PPC32 equ 0
|
||||||
|
ARCH_PPC64 equ 0
|
||||||
|
HAVE_ARMV5TE equ 0
|
||||||
|
HAVE_ARMV6 equ 0
|
||||||
|
HAVE_ARMV7 equ 0
|
||||||
|
HAVE_IWMMXT equ 0
|
||||||
|
HAVE_IWMMXT2 equ 0
|
||||||
|
HAVE_MIPS32 equ 0
|
||||||
|
HAVE_MMX equ 1
|
||||||
|
HAVE_SSE equ 1
|
||||||
|
HAVE_SSE2 equ 1
|
||||||
|
HAVE_SSE3 equ 1
|
||||||
|
HAVE_SSSE3 equ 1
|
||||||
|
HAVE_SSE4_1 equ 1
|
||||||
|
HAVE_ALTIVEC equ 0
|
||||||
|
HAVE_VPX_PORTS equ 1
|
||||||
|
HAVE_STDINT_H equ 1
|
||||||
|
HAVE_ALT_TREE_LAYOUT equ 0
|
||||||
|
HAVE_PTHREAD_H equ 1
|
||||||
|
HAVE_SYS_MMAN_H equ 1
|
||||||
|
CONFIG_EXTERNAL_BUILD equ 0
|
||||||
|
CONFIG_INSTALL_DOCS equ 0
|
||||||
|
CONFIG_INSTALL_BINS equ 1
|
||||||
|
CONFIG_INSTALL_LIBS equ 1
|
||||||
|
CONFIG_INSTALL_SRCS equ 0
|
||||||
|
CONFIG_DEBUG equ 0
|
||||||
|
CONFIG_GPROF equ 0
|
||||||
|
CONFIG_GCOV equ 0
|
||||||
|
CONFIG_RVCT equ 0
|
||||||
|
CONFIG_GCC equ 1
|
||||||
|
CONFIG_MSVS equ 0
|
||||||
|
CONFIG_PIC equ 1
|
||||||
|
CONFIG_BIG_ENDIAN equ 0
|
||||||
|
CONFIG_CODEC_SRCS equ 0
|
||||||
|
CONFIG_DEBUG_LIBS equ 0
|
||||||
|
CONFIG_FAST_UNALIGNED equ 1
|
||||||
|
CONFIG_MEM_MANAGER equ 0
|
||||||
|
CONFIG_MEM_TRACKER equ 0
|
||||||
|
CONFIG_MEM_CHECKS equ 0
|
||||||
|
CONFIG_MD5 equ 1
|
||||||
|
CONFIG_DEQUANT_TOKENS equ 0
|
||||||
|
CONFIG_DC_RECON equ 0
|
||||||
|
CONFIG_RUNTIME_CPU_DETECT equ 1
|
||||||
|
CONFIG_POSTPROC equ 1
|
||||||
|
CONFIG_MULTITHREAD equ 1
|
||||||
|
CONFIG_PSNR equ 0
|
||||||
|
CONFIG_VP8_ENCODER equ 1
|
||||||
|
CONFIG_VP8_DECODER equ 1
|
||||||
|
CONFIG_VP8 equ 1
|
||||||
|
CONFIG_ENCODERS equ 1
|
||||||
|
CONFIG_DECODERS equ 1
|
||||||
|
CONFIG_STATIC_MSVCRT equ 0
|
||||||
|
CONFIG_SPATIAL_RESAMPLING equ 1
|
||||||
|
CONFIG_REALTIME_ONLY equ 0
|
||||||
|
CONFIG_SHARED equ 0
|
||||||
|
CONFIG_SMALL equ 0
|
||||||
|
CONFIG_POSTPROC_VISUALIZER equ 0
|
||||||
|
CONFIG_OS_SUPPORT equ 1
|
||||||
@ -0,0 +1,2 @@
|
|||||||
|
static const char* const cfg = "--target=x86-linux-gcc --enable-pic --disable-install-docs --disable-install-srcs --disable-examples --disable-psnr";
|
||||||
|
const char *vpx_codec_build_config(void) {return cfg;}
|
||||||
@ -0,0 +1,64 @@
|
|||||||
|
/* This file automatically generated by configure. Do not edit! */
|
||||||
|
#define RESTRICT
|
||||||
|
#define ARCH_ARM 0
|
||||||
|
#define ARCH_MIPS 0
|
||||||
|
#define ARCH_X86 1
|
||||||
|
#define ARCH_X86_64 0
|
||||||
|
#define ARCH_PPC32 0
|
||||||
|
#define ARCH_PPC64 0
|
||||||
|
#define HAVE_ARMV5TE 0
|
||||||
|
#define HAVE_ARMV6 0
|
||||||
|
#define HAVE_ARMV7 0
|
||||||
|
#define HAVE_IWMMXT 0
|
||||||
|
#define HAVE_IWMMXT2 0
|
||||||
|
#define HAVE_MIPS32 0
|
||||||
|
#define HAVE_MMX 1
|
||||||
|
#define HAVE_SSE 1
|
||||||
|
#define HAVE_SSE2 1
|
||||||
|
#define HAVE_SSE3 1
|
||||||
|
#define HAVE_SSSE3 1
|
||||||
|
#define HAVE_SSE4_1 1
|
||||||
|
#define HAVE_ALTIVEC 0
|
||||||
|
#define HAVE_VPX_PORTS 1
|
||||||
|
#define HAVE_STDINT_H 1
|
||||||
|
#define HAVE_ALT_TREE_LAYOUT 0
|
||||||
|
#define HAVE_PTHREAD_H 1
|
||||||
|
#define HAVE_SYS_MMAN_H 1
|
||||||
|
#define CONFIG_EXTERNAL_BUILD 0
|
||||||
|
#define CONFIG_INSTALL_DOCS 0
|
||||||
|
#define CONFIG_INSTALL_BINS 1
|
||||||
|
#define CONFIG_INSTALL_LIBS 1
|
||||||
|
#define CONFIG_INSTALL_SRCS 0
|
||||||
|
#define CONFIG_DEBUG 0
|
||||||
|
#define CONFIG_GPROF 0
|
||||||
|
#define CONFIG_GCOV 0
|
||||||
|
#define CONFIG_RVCT 0
|
||||||
|
#define CONFIG_GCC 1
|
||||||
|
#define CONFIG_MSVS 0
|
||||||
|
#define CONFIG_PIC 1
|
||||||
|
#define CONFIG_BIG_ENDIAN 0
|
||||||
|
#define CONFIG_CODEC_SRCS 0
|
||||||
|
#define CONFIG_DEBUG_LIBS 0
|
||||||
|
#define CONFIG_FAST_UNALIGNED 1
|
||||||
|
#define CONFIG_MEM_MANAGER 0
|
||||||
|
#define CONFIG_MEM_TRACKER 0
|
||||||
|
#define CONFIG_MEM_CHECKS 0
|
||||||
|
#define CONFIG_MD5 1
|
||||||
|
#define CONFIG_DEQUANT_TOKENS 0
|
||||||
|
#define CONFIG_DC_RECON 0
|
||||||
|
#define CONFIG_RUNTIME_CPU_DETECT 1
|
||||||
|
#define CONFIG_POSTPROC 1
|
||||||
|
#define CONFIG_MULTITHREAD 1
|
||||||
|
#define CONFIG_PSNR 0
|
||||||
|
#define CONFIG_VP8_ENCODER 1
|
||||||
|
#define CONFIG_VP8_DECODER 1
|
||||||
|
#define CONFIG_VP8 1
|
||||||
|
#define CONFIG_ENCODERS 1
|
||||||
|
#define CONFIG_DECODERS 1
|
||||||
|
#define CONFIG_STATIC_MSVCRT 0
|
||||||
|
#define CONFIG_SPATIAL_RESAMPLING 1
|
||||||
|
#define CONFIG_REALTIME_ONLY 0
|
||||||
|
#define CONFIG_SHARED 0
|
||||||
|
#define CONFIG_SMALL 0
|
||||||
|
#define CONFIG_POSTPROC_VISUALIZER 0
|
||||||
|
#define CONFIG_OS_SUPPORT 1
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
#define VERSION_MAJOR 0
|
||||||
|
#define VERSION_MINOR 9
|
||||||
|
#define VERSION_PATCH 6
|
||||||
|
#define VERSION_EXTRA ""
|
||||||
|
#define VERSION_PACKED ((VERSION_MAJOR<<16)|(VERSION_MINOR<<8)|(VERSION_PATCH))
|
||||||
|
#define VERSION_STRING_NOSP "v0.9.6"
|
||||||
|
#define VERSION_STRING " v0.9.6"
|
||||||
@ -0,0 +1,62 @@
|
|||||||
|
ARCH_ARM equ 0
|
||||||
|
ARCH_MIPS equ 0
|
||||||
|
ARCH_X86 equ 0
|
||||||
|
ARCH_X86_64 equ 1
|
||||||
|
ARCH_PPC32 equ 0
|
||||||
|
ARCH_PPC64 equ 0
|
||||||
|
HAVE_ARMV5TE equ 0
|
||||||
|
HAVE_ARMV6 equ 0
|
||||||
|
HAVE_ARMV7 equ 0
|
||||||
|
HAVE_IWMMXT equ 0
|
||||||
|
HAVE_IWMMXT2 equ 0
|
||||||
|
HAVE_MIPS32 equ 0
|
||||||
|
HAVE_MMX equ 1
|
||||||
|
HAVE_SSE equ 1
|
||||||
|
HAVE_SSE2 equ 1
|
||||||
|
HAVE_SSE3 equ 1
|
||||||
|
HAVE_SSSE3 equ 1
|
||||||
|
HAVE_SSE4_1 equ 1
|
||||||
|
HAVE_ALTIVEC equ 0
|
||||||
|
HAVE_VPX_PORTS equ 1
|
||||||
|
HAVE_STDINT_H equ 1
|
||||||
|
HAVE_ALT_TREE_LAYOUT equ 0
|
||||||
|
HAVE_PTHREAD_H equ 1
|
||||||
|
HAVE_SYS_MMAN_H equ 1
|
||||||
|
CONFIG_EXTERNAL_BUILD equ 0
|
||||||
|
CONFIG_INSTALL_DOCS equ 0
|
||||||
|
CONFIG_INSTALL_BINS equ 1
|
||||||
|
CONFIG_INSTALL_LIBS equ 1
|
||||||
|
CONFIG_INSTALL_SRCS equ 0
|
||||||
|
CONFIG_DEBUG equ 0
|
||||||
|
CONFIG_GPROF equ 0
|
||||||
|
CONFIG_GCOV equ 0
|
||||||
|
CONFIG_RVCT equ 0
|
||||||
|
CONFIG_GCC equ 1
|
||||||
|
CONFIG_MSVS equ 0
|
||||||
|
CONFIG_PIC equ 1
|
||||||
|
CONFIG_BIG_ENDIAN equ 0
|
||||||
|
CONFIG_CODEC_SRCS equ 0
|
||||||
|
CONFIG_DEBUG_LIBS equ 0
|
||||||
|
CONFIG_FAST_UNALIGNED equ 1
|
||||||
|
CONFIG_MEM_MANAGER equ 0
|
||||||
|
CONFIG_MEM_TRACKER equ 0
|
||||||
|
CONFIG_MEM_CHECKS equ 0
|
||||||
|
CONFIG_MD5 equ 1
|
||||||
|
CONFIG_DEQUANT_TOKENS equ 0
|
||||||
|
CONFIG_DC_RECON equ 0
|
||||||
|
CONFIG_RUNTIME_CPU_DETECT equ 1
|
||||||
|
CONFIG_POSTPROC equ 1
|
||||||
|
CONFIG_MULTITHREAD equ 1
|
||||||
|
CONFIG_PSNR equ 0
|
||||||
|
CONFIG_VP8_ENCODER equ 1
|
||||||
|
CONFIG_VP8_DECODER equ 1
|
||||||
|
CONFIG_VP8 equ 1
|
||||||
|
CONFIG_ENCODERS equ 1
|
||||||
|
CONFIG_DECODERS equ 1
|
||||||
|
CONFIG_STATIC_MSVCRT equ 0
|
||||||
|
CONFIG_SPATIAL_RESAMPLING equ 1
|
||||||
|
CONFIG_REALTIME_ONLY equ 0
|
||||||
|
CONFIG_SHARED equ 0
|
||||||
|
CONFIG_SMALL equ 0
|
||||||
|
CONFIG_POSTPROC_VISUALIZER equ 0
|
||||||
|
CONFIG_OS_SUPPORT equ 1
|
||||||
@ -0,0 +1,2 @@
|
|||||||
|
static const char* const cfg = "--target=x86_64-linux-gcc --enable-pic --disable-install-docs --disable-install-srcs --disable-examples --disable-psnr";
|
||||||
|
const char *vpx_codec_build_config(void) {return cfg;}
|
||||||
64
third_party_mods/libvpx/source/config/linux/x64/vpx_config.h
Normal file
64
third_party_mods/libvpx/source/config/linux/x64/vpx_config.h
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
/* This file automatically generated by configure. Do not edit! */
|
||||||
|
#define RESTRICT
|
||||||
|
#define ARCH_ARM 0
|
||||||
|
#define ARCH_MIPS 0
|
||||||
|
#define ARCH_X86 0
|
||||||
|
#define ARCH_X86_64 1
|
||||||
|
#define ARCH_PPC32 0
|
||||||
|
#define ARCH_PPC64 0
|
||||||
|
#define HAVE_ARMV5TE 0
|
||||||
|
#define HAVE_ARMV6 0
|
||||||
|
#define HAVE_ARMV7 0
|
||||||
|
#define HAVE_IWMMXT 0
|
||||||
|
#define HAVE_IWMMXT2 0
|
||||||
|
#define HAVE_MIPS32 0
|
||||||
|
#define HAVE_MMX 1
|
||||||
|
#define HAVE_SSE 1
|
||||||
|
#define HAVE_SSE2 1
|
||||||
|
#define HAVE_SSE3 1
|
||||||
|
#define HAVE_SSSE3 1
|
||||||
|
#define HAVE_SSE4_1 1
|
||||||
|
#define HAVE_ALTIVEC 0
|
||||||
|
#define HAVE_VPX_PORTS 1
|
||||||
|
#define HAVE_STDINT_H 1
|
||||||
|
#define HAVE_ALT_TREE_LAYOUT 0
|
||||||
|
#define HAVE_PTHREAD_H 1
|
||||||
|
#define HAVE_SYS_MMAN_H 1
|
||||||
|
#define CONFIG_EXTERNAL_BUILD 0
|
||||||
|
#define CONFIG_INSTALL_DOCS 0
|
||||||
|
#define CONFIG_INSTALL_BINS 1
|
||||||
|
#define CONFIG_INSTALL_LIBS 1
|
||||||
|
#define CONFIG_INSTALL_SRCS 0
|
||||||
|
#define CONFIG_DEBUG 0
|
||||||
|
#define CONFIG_GPROF 0
|
||||||
|
#define CONFIG_GCOV 0
|
||||||
|
#define CONFIG_RVCT 0
|
||||||
|
#define CONFIG_GCC 1
|
||||||
|
#define CONFIG_MSVS 0
|
||||||
|
#define CONFIG_PIC 1
|
||||||
|
#define CONFIG_BIG_ENDIAN 0
|
||||||
|
#define CONFIG_CODEC_SRCS 0
|
||||||
|
#define CONFIG_DEBUG_LIBS 0
|
||||||
|
#define CONFIG_FAST_UNALIGNED 1
|
||||||
|
#define CONFIG_MEM_MANAGER 0
|
||||||
|
#define CONFIG_MEM_TRACKER 0
|
||||||
|
#define CONFIG_MEM_CHECKS 0
|
||||||
|
#define CONFIG_MD5 1
|
||||||
|
#define CONFIG_DEQUANT_TOKENS 0
|
||||||
|
#define CONFIG_DC_RECON 0
|
||||||
|
#define CONFIG_RUNTIME_CPU_DETECT 1
|
||||||
|
#define CONFIG_POSTPROC 1
|
||||||
|
#define CONFIG_MULTITHREAD 1
|
||||||
|
#define CONFIG_PSNR 0
|
||||||
|
#define CONFIG_VP8_ENCODER 1
|
||||||
|
#define CONFIG_VP8_DECODER 1
|
||||||
|
#define CONFIG_VP8 1
|
||||||
|
#define CONFIG_ENCODERS 1
|
||||||
|
#define CONFIG_DECODERS 1
|
||||||
|
#define CONFIG_STATIC_MSVCRT 0
|
||||||
|
#define CONFIG_SPATIAL_RESAMPLING 1
|
||||||
|
#define CONFIG_REALTIME_ONLY 0
|
||||||
|
#define CONFIG_SHARED 0
|
||||||
|
#define CONFIG_SMALL 0
|
||||||
|
#define CONFIG_POSTPROC_VISUALIZER 0
|
||||||
|
#define CONFIG_OS_SUPPORT 1
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
#define VERSION_MAJOR 0
|
||||||
|
#define VERSION_MINOR 9
|
||||||
|
#define VERSION_PATCH 6
|
||||||
|
#define VERSION_EXTRA ""
|
||||||
|
#define VERSION_PACKED ((VERSION_MAJOR<<16)|(VERSION_MINOR<<8)|(VERSION_PATCH))
|
||||||
|
#define VERSION_STRING_NOSP "v0.9.6"
|
||||||
|
#define VERSION_STRING " v0.9.6"
|
||||||
@ -0,0 +1,62 @@
|
|||||||
|
ARCH_ARM equ 0
|
||||||
|
ARCH_MIPS equ 0
|
||||||
|
ARCH_X86 equ 1
|
||||||
|
ARCH_X86_64 equ 0
|
||||||
|
ARCH_PPC32 equ 0
|
||||||
|
ARCH_PPC64 equ 0
|
||||||
|
HAVE_ARMV5TE equ 0
|
||||||
|
HAVE_ARMV6 equ 0
|
||||||
|
HAVE_ARMV7 equ 0
|
||||||
|
HAVE_IWMMXT equ 0
|
||||||
|
HAVE_IWMMXT2 equ 0
|
||||||
|
HAVE_MIPS32 equ 0
|
||||||
|
HAVE_MMX equ 1
|
||||||
|
HAVE_SSE equ 1
|
||||||
|
HAVE_SSE2 equ 1
|
||||||
|
HAVE_SSE3 equ 1
|
||||||
|
HAVE_SSSE3 equ 1
|
||||||
|
HAVE_SSE4_1 equ 1
|
||||||
|
HAVE_ALTIVEC equ 0
|
||||||
|
HAVE_VPX_PORTS equ 1
|
||||||
|
HAVE_STDINT_H equ 1
|
||||||
|
HAVE_ALT_TREE_LAYOUT equ 0
|
||||||
|
HAVE_PTHREAD_H equ 1
|
||||||
|
HAVE_SYS_MMAN_H equ 1
|
||||||
|
CONFIG_EXTERNAL_BUILD equ 0
|
||||||
|
CONFIG_INSTALL_DOCS equ 0
|
||||||
|
CONFIG_INSTALL_BINS equ 1
|
||||||
|
CONFIG_INSTALL_LIBS equ 1
|
||||||
|
CONFIG_INSTALL_SRCS equ 0
|
||||||
|
CONFIG_DEBUG equ 0
|
||||||
|
CONFIG_GPROF equ 0
|
||||||
|
CONFIG_GCOV equ 0
|
||||||
|
CONFIG_RVCT equ 0
|
||||||
|
CONFIG_GCC equ 1
|
||||||
|
CONFIG_MSVS equ 0
|
||||||
|
CONFIG_PIC equ 1
|
||||||
|
CONFIG_BIG_ENDIAN equ 0
|
||||||
|
CONFIG_CODEC_SRCS equ 0
|
||||||
|
CONFIG_DEBUG_LIBS equ 0
|
||||||
|
CONFIG_FAST_UNALIGNED equ 1
|
||||||
|
CONFIG_MEM_MANAGER equ 0
|
||||||
|
CONFIG_MEM_TRACKER equ 0
|
||||||
|
CONFIG_MEM_CHECKS equ 0
|
||||||
|
CONFIG_MD5 equ 1
|
||||||
|
CONFIG_DEQUANT_TOKENS equ 0
|
||||||
|
CONFIG_DC_RECON equ 0
|
||||||
|
CONFIG_RUNTIME_CPU_DETECT equ 1
|
||||||
|
CONFIG_POSTPROC equ 1
|
||||||
|
CONFIG_MULTITHREAD equ 1
|
||||||
|
CONFIG_PSNR equ 0
|
||||||
|
CONFIG_VP8_ENCODER equ 1
|
||||||
|
CONFIG_VP8_DECODER equ 1
|
||||||
|
CONFIG_VP8 equ 1
|
||||||
|
CONFIG_ENCODERS equ 1
|
||||||
|
CONFIG_DECODERS equ 1
|
||||||
|
CONFIG_STATIC_MSVCRT equ 0
|
||||||
|
CONFIG_SPATIAL_RESAMPLING equ 1
|
||||||
|
CONFIG_REALTIME_ONLY equ 0
|
||||||
|
CONFIG_SHARED equ 0
|
||||||
|
CONFIG_SMALL equ 0
|
||||||
|
CONFIG_POSTPROC_VISUALIZER equ 0
|
||||||
|
CONFIG_OS_SUPPORT equ 1
|
||||||
@ -0,0 +1,2 @@
|
|||||||
|
static const char* const cfg = "--target=x86-darwin9-gcc --enable-pic --disable-install-docs --disable-install-srcs --disable-examples --disable-psnr";
|
||||||
|
const char *vpx_codec_build_config(void) {return cfg;}
|
||||||
64
third_party_mods/libvpx/source/config/mac/ia32/vpx_config.h
Normal file
64
third_party_mods/libvpx/source/config/mac/ia32/vpx_config.h
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
/* This file automatically generated by configure. Do not edit! */
|
||||||
|
#define RESTRICT
|
||||||
|
#define ARCH_ARM 0
|
||||||
|
#define ARCH_MIPS 0
|
||||||
|
#define ARCH_X86 1
|
||||||
|
#define ARCH_X86_64 0
|
||||||
|
#define ARCH_PPC32 0
|
||||||
|
#define ARCH_PPC64 0
|
||||||
|
#define HAVE_ARMV5TE 0
|
||||||
|
#define HAVE_ARMV6 0
|
||||||
|
#define HAVE_ARMV7 0
|
||||||
|
#define HAVE_IWMMXT 0
|
||||||
|
#define HAVE_IWMMXT2 0
|
||||||
|
#define HAVE_MIPS32 0
|
||||||
|
#define HAVE_MMX 1
|
||||||
|
#define HAVE_SSE 1
|
||||||
|
#define HAVE_SSE2 1
|
||||||
|
#define HAVE_SSE3 1
|
||||||
|
#define HAVE_SSSE3 1
|
||||||
|
#define HAVE_SSE4_1 1
|
||||||
|
#define HAVE_ALTIVEC 0
|
||||||
|
#define HAVE_VPX_PORTS 1
|
||||||
|
#define HAVE_STDINT_H 1
|
||||||
|
#define HAVE_ALT_TREE_LAYOUT 0
|
||||||
|
#define HAVE_PTHREAD_H 1
|
||||||
|
#define HAVE_SYS_MMAN_H 1
|
||||||
|
#define CONFIG_EXTERNAL_BUILD 0
|
||||||
|
#define CONFIG_INSTALL_DOCS 0
|
||||||
|
#define CONFIG_INSTALL_BINS 1
|
||||||
|
#define CONFIG_INSTALL_LIBS 1
|
||||||
|
#define CONFIG_INSTALL_SRCS 0
|
||||||
|
#define CONFIG_DEBUG 0
|
||||||
|
#define CONFIG_GPROF 0
|
||||||
|
#define CONFIG_GCOV 0
|
||||||
|
#define CONFIG_RVCT 0
|
||||||
|
#define CONFIG_GCC 1
|
||||||
|
#define CONFIG_MSVS 0
|
||||||
|
#define CONFIG_PIC 1
|
||||||
|
#define CONFIG_BIG_ENDIAN 0
|
||||||
|
#define CONFIG_CODEC_SRCS 0
|
||||||
|
#define CONFIG_DEBUG_LIBS 0
|
||||||
|
#define CONFIG_FAST_UNALIGNED 1
|
||||||
|
#define CONFIG_MEM_MANAGER 0
|
||||||
|
#define CONFIG_MEM_TRACKER 0
|
||||||
|
#define CONFIG_MEM_CHECKS 0
|
||||||
|
#define CONFIG_MD5 1
|
||||||
|
#define CONFIG_DEQUANT_TOKENS 0
|
||||||
|
#define CONFIG_DC_RECON 0
|
||||||
|
#define CONFIG_RUNTIME_CPU_DETECT 1
|
||||||
|
#define CONFIG_POSTPROC 1
|
||||||
|
#define CONFIG_MULTITHREAD 1
|
||||||
|
#define CONFIG_PSNR 0
|
||||||
|
#define CONFIG_VP8_ENCODER 1
|
||||||
|
#define CONFIG_VP8_DECODER 1
|
||||||
|
#define CONFIG_VP8 1
|
||||||
|
#define CONFIG_ENCODERS 1
|
||||||
|
#define CONFIG_DECODERS 1
|
||||||
|
#define CONFIG_STATIC_MSVCRT 0
|
||||||
|
#define CONFIG_SPATIAL_RESAMPLING 1
|
||||||
|
#define CONFIG_REALTIME_ONLY 0
|
||||||
|
#define CONFIG_SHARED 0
|
||||||
|
#define CONFIG_SMALL 0
|
||||||
|
#define CONFIG_POSTPROC_VISUALIZER 0
|
||||||
|
#define CONFIG_OS_SUPPORT 1
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
#define VERSION_MAJOR 0
|
||||||
|
#define VERSION_MINOR 9
|
||||||
|
#define VERSION_PATCH 6
|
||||||
|
#define VERSION_EXTRA ""
|
||||||
|
#define VERSION_PACKED ((VERSION_MAJOR<<16)|(VERSION_MINOR<<8)|(VERSION_PATCH))
|
||||||
|
#define VERSION_STRING_NOSP "v0.9.6"
|
||||||
|
#define VERSION_STRING " v0.9.6"
|
||||||
62
third_party_mods/libvpx/source/config/mac/x64/vpx_config.asm
Normal file
62
third_party_mods/libvpx/source/config/mac/x64/vpx_config.asm
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
ARCH_ARM equ 0
|
||||||
|
ARCH_MIPS equ 0
|
||||||
|
ARCH_X86 equ 0
|
||||||
|
ARCH_X86_64 equ 1
|
||||||
|
ARCH_PPC32 equ 0
|
||||||
|
ARCH_PPC64 equ 0
|
||||||
|
HAVE_ARMV5TE equ 0
|
||||||
|
HAVE_ARMV6 equ 0
|
||||||
|
HAVE_ARMV7 equ 0
|
||||||
|
HAVE_IWMMXT equ 0
|
||||||
|
HAVE_IWMMXT2 equ 0
|
||||||
|
HAVE_MIPS32 equ 0
|
||||||
|
HAVE_MMX equ 1
|
||||||
|
HAVE_SSE equ 1
|
||||||
|
HAVE_SSE2 equ 1
|
||||||
|
HAVE_SSE3 equ 1
|
||||||
|
HAVE_SSSE3 equ 1
|
||||||
|
HAVE_SSE4_1 equ 1
|
||||||
|
HAVE_ALTIVEC equ 0
|
||||||
|
HAVE_VPX_PORTS equ 1
|
||||||
|
HAVE_STDINT_H equ 1
|
||||||
|
HAVE_ALT_TREE_LAYOUT equ 0
|
||||||
|
HAVE_PTHREAD_H equ 1
|
||||||
|
HAVE_SYS_MMAN_H equ 1
|
||||||
|
CONFIG_EXTERNAL_BUILD equ 0
|
||||||
|
CONFIG_INSTALL_DOCS equ 0
|
||||||
|
CONFIG_INSTALL_BINS equ 1
|
||||||
|
CONFIG_INSTALL_LIBS equ 1
|
||||||
|
CONFIG_INSTALL_SRCS equ 0
|
||||||
|
CONFIG_DEBUG equ 0
|
||||||
|
CONFIG_GPROF equ 0
|
||||||
|
CONFIG_GCOV equ 0
|
||||||
|
CONFIG_RVCT equ 0
|
||||||
|
CONFIG_GCC equ 1
|
||||||
|
CONFIG_MSVS equ 0
|
||||||
|
CONFIG_PIC equ 1
|
||||||
|
CONFIG_BIG_ENDIAN equ 0
|
||||||
|
CONFIG_CODEC_SRCS equ 0
|
||||||
|
CONFIG_DEBUG_LIBS equ 0
|
||||||
|
CONFIG_FAST_UNALIGNED equ 1
|
||||||
|
CONFIG_MEM_MANAGER equ 0
|
||||||
|
CONFIG_MEM_TRACKER equ 0
|
||||||
|
CONFIG_MEM_CHECKS equ 0
|
||||||
|
CONFIG_MD5 equ 1
|
||||||
|
CONFIG_DEQUANT_TOKENS equ 0
|
||||||
|
CONFIG_DC_RECON equ 0
|
||||||
|
CONFIG_RUNTIME_CPU_DETECT equ 1
|
||||||
|
CONFIG_POSTPROC equ 1
|
||||||
|
CONFIG_MULTITHREAD equ 1
|
||||||
|
CONFIG_PSNR equ 0
|
||||||
|
CONFIG_VP8_ENCODER equ 1
|
||||||
|
CONFIG_VP8_DECODER equ 1
|
||||||
|
CONFIG_VP8 equ 1
|
||||||
|
CONFIG_ENCODERS equ 1
|
||||||
|
CONFIG_DECODERS equ 1
|
||||||
|
CONFIG_STATIC_MSVCRT equ 0
|
||||||
|
CONFIG_SPATIAL_RESAMPLING equ 1
|
||||||
|
CONFIG_REALTIME_ONLY equ 0
|
||||||
|
CONFIG_SHARED equ 0
|
||||||
|
CONFIG_SMALL equ 0
|
||||||
|
CONFIG_POSTPROC_VISUALIZER equ 0
|
||||||
|
CONFIG_OS_SUPPORT equ 1
|
||||||
@ -0,0 +1,2 @@
|
|||||||
|
static const char* const cfg = "--target=x86_64-darwin10-gcc --enable-pic --disable-install-docs --disable-install-srcs --disable-examples --disable-psnr";
|
||||||
|
const char *vpx_codec_build_config(void) {return cfg;}
|
||||||
64
third_party_mods/libvpx/source/config/mac/x64/vpx_config.h
Normal file
64
third_party_mods/libvpx/source/config/mac/x64/vpx_config.h
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
/* This file automatically generated by configure. Do not edit! */
|
||||||
|
#define RESTRICT
|
||||||
|
#define ARCH_ARM 0
|
||||||
|
#define ARCH_MIPS 0
|
||||||
|
#define ARCH_X86 0
|
||||||
|
#define ARCH_X86_64 1
|
||||||
|
#define ARCH_PPC32 0
|
||||||
|
#define ARCH_PPC64 0
|
||||||
|
#define HAVE_ARMV5TE 0
|
||||||
|
#define HAVE_ARMV6 0
|
||||||
|
#define HAVE_ARMV7 0
|
||||||
|
#define HAVE_IWMMXT 0
|
||||||
|
#define HAVE_IWMMXT2 0
|
||||||
|
#define HAVE_MIPS32 0
|
||||||
|
#define HAVE_MMX 1
|
||||||
|
#define HAVE_SSE 1
|
||||||
|
#define HAVE_SSE2 1
|
||||||
|
#define HAVE_SSE3 1
|
||||||
|
#define HAVE_SSSE3 1
|
||||||
|
#define HAVE_SSE4_1 1
|
||||||
|
#define HAVE_ALTIVEC 0
|
||||||
|
#define HAVE_VPX_PORTS 1
|
||||||
|
#define HAVE_STDINT_H 1
|
||||||
|
#define HAVE_ALT_TREE_LAYOUT 0
|
||||||
|
#define HAVE_PTHREAD_H 1
|
||||||
|
#define HAVE_SYS_MMAN_H 1
|
||||||
|
#define CONFIG_EXTERNAL_BUILD 0
|
||||||
|
#define CONFIG_INSTALL_DOCS 0
|
||||||
|
#define CONFIG_INSTALL_BINS 1
|
||||||
|
#define CONFIG_INSTALL_LIBS 1
|
||||||
|
#define CONFIG_INSTALL_SRCS 0
|
||||||
|
#define CONFIG_DEBUG 0
|
||||||
|
#define CONFIG_GPROF 0
|
||||||
|
#define CONFIG_GCOV 0
|
||||||
|
#define CONFIG_RVCT 0
|
||||||
|
#define CONFIG_GCC 1
|
||||||
|
#define CONFIG_MSVS 0
|
||||||
|
#define CONFIG_PIC 1
|
||||||
|
#define CONFIG_BIG_ENDIAN 0
|
||||||
|
#define CONFIG_CODEC_SRCS 0
|
||||||
|
#define CONFIG_DEBUG_LIBS 0
|
||||||
|
#define CONFIG_FAST_UNALIGNED 1
|
||||||
|
#define CONFIG_MEM_MANAGER 0
|
||||||
|
#define CONFIG_MEM_TRACKER 0
|
||||||
|
#define CONFIG_MEM_CHECKS 0
|
||||||
|
#define CONFIG_MD5 1
|
||||||
|
#define CONFIG_DEQUANT_TOKENS 0
|
||||||
|
#define CONFIG_DC_RECON 0
|
||||||
|
#define CONFIG_RUNTIME_CPU_DETECT 1
|
||||||
|
#define CONFIG_POSTPROC 1
|
||||||
|
#define CONFIG_MULTITHREAD 1
|
||||||
|
#define CONFIG_PSNR 0
|
||||||
|
#define CONFIG_VP8_ENCODER 1
|
||||||
|
#define CONFIG_VP8_DECODER 1
|
||||||
|
#define CONFIG_VP8 1
|
||||||
|
#define CONFIG_ENCODERS 1
|
||||||
|
#define CONFIG_DECODERS 1
|
||||||
|
#define CONFIG_STATIC_MSVCRT 0
|
||||||
|
#define CONFIG_SPATIAL_RESAMPLING 1
|
||||||
|
#define CONFIG_REALTIME_ONLY 0
|
||||||
|
#define CONFIG_SHARED 0
|
||||||
|
#define CONFIG_SMALL 0
|
||||||
|
#define CONFIG_POSTPROC_VISUALIZER 0
|
||||||
|
#define CONFIG_OS_SUPPORT 1
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
#define VERSION_MAJOR 0
|
||||||
|
#define VERSION_MINOR 9
|
||||||
|
#define VERSION_PATCH 6
|
||||||
|
#define VERSION_EXTRA ""
|
||||||
|
#define VERSION_PACKED ((VERSION_MAJOR<<16)|(VERSION_MINOR<<8)|(VERSION_PATCH))
|
||||||
|
#define VERSION_STRING_NOSP "v0.9.6"
|
||||||
|
#define VERSION_STRING " v0.9.6"
|
||||||
@ -0,0 +1,62 @@
|
|||||||
|
ARCH_ARM equ 0
|
||||||
|
ARCH_MIPS equ 0
|
||||||
|
ARCH_X86 equ 1
|
||||||
|
ARCH_X86_64 equ 0
|
||||||
|
ARCH_PPC32 equ 0
|
||||||
|
ARCH_PPC64 equ 0
|
||||||
|
HAVE_ARMV5TE equ 0
|
||||||
|
HAVE_ARMV6 equ 0
|
||||||
|
HAVE_ARMV7 equ 0
|
||||||
|
HAVE_IWMMXT equ 0
|
||||||
|
HAVE_IWMMXT2 equ 0
|
||||||
|
HAVE_MIPS32 equ 0
|
||||||
|
HAVE_MMX equ 1
|
||||||
|
HAVE_SSE equ 1
|
||||||
|
HAVE_SSE2 equ 1
|
||||||
|
HAVE_SSE3 equ 1
|
||||||
|
HAVE_SSSE3 equ 1
|
||||||
|
HAVE_SSE4_1 equ 1
|
||||||
|
HAVE_ALTIVEC equ 0
|
||||||
|
HAVE_VPX_PORTS equ 1
|
||||||
|
HAVE_STDINT_H equ 0
|
||||||
|
HAVE_ALT_TREE_LAYOUT equ 0
|
||||||
|
HAVE_PTHREAD_H equ 0
|
||||||
|
HAVE_SYS_MMAN_H equ 0
|
||||||
|
CONFIG_EXTERNAL_BUILD equ 1
|
||||||
|
CONFIG_INSTALL_DOCS equ 0
|
||||||
|
CONFIG_INSTALL_BINS equ 1
|
||||||
|
CONFIG_INSTALL_LIBS equ 1
|
||||||
|
CONFIG_INSTALL_SRCS equ 0
|
||||||
|
CONFIG_DEBUG equ 0
|
||||||
|
CONFIG_GPROF equ 0
|
||||||
|
CONFIG_GCOV equ 0
|
||||||
|
CONFIG_RVCT equ 0
|
||||||
|
CONFIG_GCC equ 0
|
||||||
|
CONFIG_MSVS equ 1
|
||||||
|
CONFIG_PIC equ 1
|
||||||
|
CONFIG_BIG_ENDIAN equ 0
|
||||||
|
CONFIG_CODEC_SRCS equ 0
|
||||||
|
CONFIG_DEBUG_LIBS equ 0
|
||||||
|
CONFIG_FAST_UNALIGNED equ 1
|
||||||
|
CONFIG_MEM_MANAGER equ 0
|
||||||
|
CONFIG_MEM_TRACKER equ 0
|
||||||
|
CONFIG_MEM_CHECKS equ 0
|
||||||
|
CONFIG_MD5 equ 1
|
||||||
|
CONFIG_DEQUANT_TOKENS equ 0
|
||||||
|
CONFIG_DC_RECON equ 0
|
||||||
|
CONFIG_RUNTIME_CPU_DETECT equ 1
|
||||||
|
CONFIG_POSTPROC equ 1
|
||||||
|
CONFIG_MULTITHREAD equ 1
|
||||||
|
CONFIG_PSNR equ 0
|
||||||
|
CONFIG_VP8_ENCODER equ 1
|
||||||
|
CONFIG_VP8_DECODER equ 1
|
||||||
|
CONFIG_VP8 equ 1
|
||||||
|
CONFIG_ENCODERS equ 1
|
||||||
|
CONFIG_DECODERS equ 1
|
||||||
|
CONFIG_STATIC_MSVCRT equ 0
|
||||||
|
CONFIG_SPATIAL_RESAMPLING equ 1
|
||||||
|
CONFIG_REALTIME_ONLY equ 0
|
||||||
|
CONFIG_SHARED equ 0
|
||||||
|
CONFIG_SMALL equ 0
|
||||||
|
CONFIG_POSTPROC_VISUALIZER equ 0
|
||||||
|
CONFIG_OS_SUPPORT equ 1
|
||||||
@ -0,0 +1,2 @@
|
|||||||
|
static const char* const cfg = "--target=x86-win32-vs8 --enable-pic --disable-install-docs --disable-install-srcs --disable-examples --disable-psnr";
|
||||||
|
const char *vpx_codec_build_config(void) {return cfg;}
|
||||||
64
third_party_mods/libvpx/source/config/win/ia32/vpx_config.h
Normal file
64
third_party_mods/libvpx/source/config/win/ia32/vpx_config.h
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
/* This file automatically generated by configure. Do not edit! */
|
||||||
|
#define RESTRICT
|
||||||
|
#define ARCH_ARM 0
|
||||||
|
#define ARCH_MIPS 0
|
||||||
|
#define ARCH_X86 1
|
||||||
|
#define ARCH_X86_64 0
|
||||||
|
#define ARCH_PPC32 0
|
||||||
|
#define ARCH_PPC64 0
|
||||||
|
#define HAVE_ARMV5TE 0
|
||||||
|
#define HAVE_ARMV6 0
|
||||||
|
#define HAVE_ARMV7 0
|
||||||
|
#define HAVE_IWMMXT 0
|
||||||
|
#define HAVE_IWMMXT2 0
|
||||||
|
#define HAVE_MIPS32 0
|
||||||
|
#define HAVE_MMX 1
|
||||||
|
#define HAVE_SSE 1
|
||||||
|
#define HAVE_SSE2 1
|
||||||
|
#define HAVE_SSE3 1
|
||||||
|
#define HAVE_SSSE3 1
|
||||||
|
#define HAVE_SSE4_1 1
|
||||||
|
#define HAVE_ALTIVEC 0
|
||||||
|
#define HAVE_VPX_PORTS 1
|
||||||
|
#define HAVE_STDINT_H 0
|
||||||
|
#define HAVE_ALT_TREE_LAYOUT 0
|
||||||
|
#define HAVE_PTHREAD_H 0
|
||||||
|
#define HAVE_SYS_MMAN_H 0
|
||||||
|
#define CONFIG_EXTERNAL_BUILD 1
|
||||||
|
#define CONFIG_INSTALL_DOCS 0
|
||||||
|
#define CONFIG_INSTALL_BINS 1
|
||||||
|
#define CONFIG_INSTALL_LIBS 1
|
||||||
|
#define CONFIG_INSTALL_SRCS 0
|
||||||
|
#define CONFIG_DEBUG 0
|
||||||
|
#define CONFIG_GPROF 0
|
||||||
|
#define CONFIG_GCOV 0
|
||||||
|
#define CONFIG_RVCT 0
|
||||||
|
#define CONFIG_GCC 0
|
||||||
|
#define CONFIG_MSVS 1
|
||||||
|
#define CONFIG_PIC 1
|
||||||
|
#define CONFIG_BIG_ENDIAN 0
|
||||||
|
#define CONFIG_CODEC_SRCS 0
|
||||||
|
#define CONFIG_DEBUG_LIBS 0
|
||||||
|
#define CONFIG_FAST_UNALIGNED 1
|
||||||
|
#define CONFIG_MEM_MANAGER 0
|
||||||
|
#define CONFIG_MEM_TRACKER 0
|
||||||
|
#define CONFIG_MEM_CHECKS 0
|
||||||
|
#define CONFIG_MD5 1
|
||||||
|
#define CONFIG_DEQUANT_TOKENS 0
|
||||||
|
#define CONFIG_DC_RECON 0
|
||||||
|
#define CONFIG_RUNTIME_CPU_DETECT 1
|
||||||
|
#define CONFIG_POSTPROC 1
|
||||||
|
#define CONFIG_MULTITHREAD 1
|
||||||
|
#define CONFIG_PSNR 0
|
||||||
|
#define CONFIG_VP8_ENCODER 1
|
||||||
|
#define CONFIG_VP8_DECODER 1
|
||||||
|
#define CONFIG_VP8 1
|
||||||
|
#define CONFIG_ENCODERS 1
|
||||||
|
#define CONFIG_DECODERS 1
|
||||||
|
#define CONFIG_STATIC_MSVCRT 0
|
||||||
|
#define CONFIG_SPATIAL_RESAMPLING 1
|
||||||
|
#define CONFIG_REALTIME_ONLY 0
|
||||||
|
#define CONFIG_SHARED 0
|
||||||
|
#define CONFIG_SMALL 0
|
||||||
|
#define CONFIG_POSTPROC_VISUALIZER 0
|
||||||
|
#define CONFIG_OS_SUPPORT 1
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
#define VERSION_MAJOR 0
|
||||||
|
#define VERSION_MINOR 9
|
||||||
|
#define VERSION_PATCH 6
|
||||||
|
#define VERSION_EXTRA ""
|
||||||
|
#define VERSION_PACKED ((VERSION_MAJOR<<16)|(VERSION_MINOR<<8)|(VERSION_PATCH))
|
||||||
|
#define VERSION_STRING_NOSP "v0.9.6"
|
||||||
|
#define VERSION_STRING " v0.9.6"
|
||||||
62
third_party_mods/libvpx/source/config/win/x64/vpx_config.asm
Normal file
62
third_party_mods/libvpx/source/config/win/x64/vpx_config.asm
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
ARCH_ARM equ 0
|
||||||
|
ARCH_MIPS equ 0
|
||||||
|
ARCH_X86 equ 0
|
||||||
|
ARCH_X86_64 equ 1
|
||||||
|
ARCH_PPC32 equ 0
|
||||||
|
ARCH_PPC64 equ 0
|
||||||
|
HAVE_ARMV5TE equ 0
|
||||||
|
HAVE_ARMV6 equ 0
|
||||||
|
HAVE_ARMV7 equ 0
|
||||||
|
HAVE_IWMMXT equ 0
|
||||||
|
HAVE_IWMMXT2 equ 0
|
||||||
|
HAVE_MIPS32 equ 0
|
||||||
|
HAVE_MMX equ 1
|
||||||
|
HAVE_SSE equ 1
|
||||||
|
HAVE_SSE2 equ 1
|
||||||
|
HAVE_SSE3 equ 1
|
||||||
|
HAVE_SSSE3 equ 1
|
||||||
|
HAVE_SSE4_1 equ 1
|
||||||
|
HAVE_ALTIVEC equ 0
|
||||||
|
HAVE_VPX_PORTS equ 1
|
||||||
|
HAVE_STDINT_H equ 0
|
||||||
|
HAVE_ALT_TREE_LAYOUT equ 0
|
||||||
|
HAVE_PTHREAD_H equ 0
|
||||||
|
HAVE_SYS_MMAN_H equ 0
|
||||||
|
CONFIG_EXTERNAL_BUILD equ 1
|
||||||
|
CONFIG_INSTALL_DOCS equ 0
|
||||||
|
CONFIG_INSTALL_BINS equ 1
|
||||||
|
CONFIG_INSTALL_LIBS equ 1
|
||||||
|
CONFIG_INSTALL_SRCS equ 0
|
||||||
|
CONFIG_DEBUG equ 0
|
||||||
|
CONFIG_GPROF equ 0
|
||||||
|
CONFIG_GCOV equ 0
|
||||||
|
CONFIG_RVCT equ 0
|
||||||
|
CONFIG_GCC equ 0
|
||||||
|
CONFIG_MSVS equ 1
|
||||||
|
CONFIG_PIC equ 1
|
||||||
|
CONFIG_BIG_ENDIAN equ 0
|
||||||
|
CONFIG_CODEC_SRCS equ 0
|
||||||
|
CONFIG_DEBUG_LIBS equ 0
|
||||||
|
CONFIG_FAST_UNALIGNED equ 1
|
||||||
|
CONFIG_MEM_MANAGER equ 0
|
||||||
|
CONFIG_MEM_TRACKER equ 0
|
||||||
|
CONFIG_MEM_CHECKS equ 0
|
||||||
|
CONFIG_MD5 equ 1
|
||||||
|
CONFIG_DEQUANT_TOKENS equ 0
|
||||||
|
CONFIG_DC_RECON equ 0
|
||||||
|
CONFIG_RUNTIME_CPU_DETECT equ 1
|
||||||
|
CONFIG_POSTPROC equ 1
|
||||||
|
CONFIG_MULTITHREAD equ 1
|
||||||
|
CONFIG_PSNR equ 0
|
||||||
|
CONFIG_VP8_ENCODER equ 1
|
||||||
|
CONFIG_VP8_DECODER equ 1
|
||||||
|
CONFIG_VP8 equ 1
|
||||||
|
CONFIG_ENCODERS equ 1
|
||||||
|
CONFIG_DECODERS equ 1
|
||||||
|
CONFIG_STATIC_MSVCRT equ 0
|
||||||
|
CONFIG_SPATIAL_RESAMPLING equ 1
|
||||||
|
CONFIG_REALTIME_ONLY equ 0
|
||||||
|
CONFIG_SHARED equ 0
|
||||||
|
CONFIG_SMALL equ 0
|
||||||
|
CONFIG_POSTPROC_VISUALIZER equ 0
|
||||||
|
CONFIG_OS_SUPPORT equ 1
|
||||||
@ -0,0 +1,2 @@
|
|||||||
|
static const char* const cfg = "--target=x86_64-win64-vs8 --enable-pic --disable-install-docs --disable-install-srcs --disable-examples --disable-psnr";
|
||||||
|
const char *vpx_codec_build_config(void) {return cfg;}
|
||||||
64
third_party_mods/libvpx/source/config/win/x64/vpx_config.h
Normal file
64
third_party_mods/libvpx/source/config/win/x64/vpx_config.h
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
/* This file automatically generated by configure. Do not edit! */
|
||||||
|
#define RESTRICT
|
||||||
|
#define ARCH_ARM 0
|
||||||
|
#define ARCH_MIPS 0
|
||||||
|
#define ARCH_X86 0
|
||||||
|
#define ARCH_X86_64 1
|
||||||
|
#define ARCH_PPC32 0
|
||||||
|
#define ARCH_PPC64 0
|
||||||
|
#define HAVE_ARMV5TE 0
|
||||||
|
#define HAVE_ARMV6 0
|
||||||
|
#define HAVE_ARMV7 0
|
||||||
|
#define HAVE_IWMMXT 0
|
||||||
|
#define HAVE_IWMMXT2 0
|
||||||
|
#define HAVE_MIPS32 0
|
||||||
|
#define HAVE_MMX 1
|
||||||
|
#define HAVE_SSE 1
|
||||||
|
#define HAVE_SSE2 1
|
||||||
|
#define HAVE_SSE3 1
|
||||||
|
#define HAVE_SSSE3 1
|
||||||
|
#define HAVE_SSE4_1 1
|
||||||
|
#define HAVE_ALTIVEC 0
|
||||||
|
#define HAVE_VPX_PORTS 1
|
||||||
|
#define HAVE_STDINT_H 0
|
||||||
|
#define HAVE_ALT_TREE_LAYOUT 0
|
||||||
|
#define HAVE_PTHREAD_H 0
|
||||||
|
#define HAVE_SYS_MMAN_H 0
|
||||||
|
#define CONFIG_EXTERNAL_BUILD 1
|
||||||
|
#define CONFIG_INSTALL_DOCS 0
|
||||||
|
#define CONFIG_INSTALL_BINS 1
|
||||||
|
#define CONFIG_INSTALL_LIBS 1
|
||||||
|
#define CONFIG_INSTALL_SRCS 0
|
||||||
|
#define CONFIG_DEBUG 0
|
||||||
|
#define CONFIG_GPROF 0
|
||||||
|
#define CONFIG_GCOV 0
|
||||||
|
#define CONFIG_RVCT 0
|
||||||
|
#define CONFIG_GCC 0
|
||||||
|
#define CONFIG_MSVS 1
|
||||||
|
#define CONFIG_PIC 1
|
||||||
|
#define CONFIG_BIG_ENDIAN 0
|
||||||
|
#define CONFIG_CODEC_SRCS 0
|
||||||
|
#define CONFIG_DEBUG_LIBS 0
|
||||||
|
#define CONFIG_FAST_UNALIGNED 1
|
||||||
|
#define CONFIG_MEM_MANAGER 0
|
||||||
|
#define CONFIG_MEM_TRACKER 0
|
||||||
|
#define CONFIG_MEM_CHECKS 0
|
||||||
|
#define CONFIG_MD5 1
|
||||||
|
#define CONFIG_DEQUANT_TOKENS 0
|
||||||
|
#define CONFIG_DC_RECON 0
|
||||||
|
#define CONFIG_RUNTIME_CPU_DETECT 1
|
||||||
|
#define CONFIG_POSTPROC 1
|
||||||
|
#define CONFIG_MULTITHREAD 1
|
||||||
|
#define CONFIG_PSNR 0
|
||||||
|
#define CONFIG_VP8_ENCODER 1
|
||||||
|
#define CONFIG_VP8_DECODER 1
|
||||||
|
#define CONFIG_VP8 1
|
||||||
|
#define CONFIG_ENCODERS 1
|
||||||
|
#define CONFIG_DECODERS 1
|
||||||
|
#define CONFIG_STATIC_MSVCRT 0
|
||||||
|
#define CONFIG_SPATIAL_RESAMPLING 1
|
||||||
|
#define CONFIG_REALTIME_ONLY 0
|
||||||
|
#define CONFIG_SHARED 0
|
||||||
|
#define CONFIG_SMALL 0
|
||||||
|
#define CONFIG_POSTPROC_VISUALIZER 0
|
||||||
|
#define CONFIG_OS_SUPPORT 1
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
#define VERSION_MAJOR 0
|
||||||
|
#define VERSION_MINOR 9
|
||||||
|
#define VERSION_PATCH 6
|
||||||
|
#define VERSION_EXTRA ""
|
||||||
|
#define VERSION_PACKED ((VERSION_MAJOR<<16)|(VERSION_MINOR<<8)|(VERSION_PATCH))
|
||||||
|
#define VERSION_STRING_NOSP "v0.9.6"
|
||||||
|
#define VERSION_STRING " v0.9.6"
|
||||||
64
third_party_mods/mslpl/LICENSE
Normal file
64
third_party_mods/mslpl/LICENSE
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
This license governs use of code marked as “sample” or “example” available on
|
||||||
|
this web site without a license agreement, as provided under the section above
|
||||||
|
titled “NOTICE SPECIFIC TO SOFTWARE AVAILABLE ON THIS WEB SITE.” If you use
|
||||||
|
such code (the “software”), you accept this license. If you do not accept the
|
||||||
|
license, do not use the software.
|
||||||
|
|
||||||
|
1. Definitions
|
||||||
|
|
||||||
|
The terms “reproduce,” “reproduction,” “derivative works,” and “distribution”
|
||||||
|
have the same meaning here as under U.S. copyright law.
|
||||||
|
|
||||||
|
A “contribution” is the original software, or any additions or changes to the
|
||||||
|
software.
|
||||||
|
|
||||||
|
A “contributor” is any person that distributes its contribution under this
|
||||||
|
license.
|
||||||
|
|
||||||
|
“Licensed patents” are a contributor’s patent claims that read directly on its
|
||||||
|
contribution.
|
||||||
|
|
||||||
|
2. Grant of Rights
|
||||||
|
|
||||||
|
(A) Copyright Grant - Subject to the terms of this license, including the
|
||||||
|
license conditions and limitations in section 3, each contributor grants you a
|
||||||
|
non-exclusive, worldwide, royalty-free copyright license to reproduce its
|
||||||
|
contribution, prepare derivative works of its contribution, and distribute its
|
||||||
|
contribution or any derivative works that you create.
|
||||||
|
|
||||||
|
(B) Patent Grant - Subject to the terms of this license, including the license
|
||||||
|
conditions and limitations in section 3, each contributor grants you a
|
||||||
|
non-exclusive, worldwide, royalty-free license under its licensed patents to
|
||||||
|
make, have made, use, sell, offer for sale, import, and/or otherwise dispose
|
||||||
|
of its contribution in the software or derivative works of the contribution in
|
||||||
|
the software.
|
||||||
|
|
||||||
|
3. Conditions and Limitations
|
||||||
|
|
||||||
|
(A) No Trademark License- This license does not grant you rights to use any
|
||||||
|
contributors’ name, logo, or trademarks.
|
||||||
|
|
||||||
|
(B) If you bring a patent claim against any contributor over patents that you
|
||||||
|
claim are infringed by the software, your patent license from such contributor
|
||||||
|
to the software ends automatically.
|
||||||
|
|
||||||
|
(C) If you distribute any portion of the software, you must retain all
|
||||||
|
copyright, patent, trademark, and attribution notices that are present in the
|
||||||
|
software.
|
||||||
|
|
||||||
|
(D) If you distribute any portion of the software in source code form, you may
|
||||||
|
do so only under this license by including a complete copy of this license
|
||||||
|
with your distribution. If you distribute any portion of the software in
|
||||||
|
compiled or object code form, you may only do so under a license that complies
|
||||||
|
with this license.
|
||||||
|
|
||||||
|
(E) The software is licensed “as-is.” You bear the risk of using it. The
|
||||||
|
contributors give no express warranties, guarantees or conditions. You may
|
||||||
|
have additional consumer rights under your local laws which this license
|
||||||
|
cannot change. To the extent permitted under your local laws, the contributors
|
||||||
|
exclude the implied warranties of merchantability, fitness for a particular
|
||||||
|
purpose and non-infringement.
|
||||||
|
|
||||||
|
(F) Platform Limitation - The licenses granted in sections 2(A) and 2(B)
|
||||||
|
extend only to the software or derivative works that you create that run on a
|
||||||
|
Microsoft Windows operating system product.
|
||||||
Loading…
x
Reference in New Issue
Block a user