Update libjingle to 61168196

R=mallinath@webrtc.org

Review URL: https://webrtc-codereview.appspot.com/8139004

git-svn-id: http://webrtc.googlecode.com/svn/trunk@5502 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
sergeyu@chromium.org 2014-02-07 19:03:26 +00:00
parent 9510e53cc0
commit 9cf037b831
36 changed files with 1715 additions and 687 deletions

View File

@ -668,7 +668,7 @@ public class PeerConnectionTest extends TestCase {
offeringExpectations.expectMessage(expectedBinaryMessage, true);
assertTrue(answeringExpectations.dataChannel.send(
new DataChannel.Buffer(
ByteBuffer.wrap(new byte[] { 1, 2, 3, 4, 5 } ), true)));
ByteBuffer.wrap(new byte[] { 1, 2, 3, 4, 5 }), true)));
offeringExpectations.waitForAllExpectationsToBeSatisfied();
offeringExpectations.expectStateChange(DataChannel.State.CLOSING);

View File

@ -70,6 +70,9 @@ bool FromConstraints(const MediaConstraintsInterface::Constraints& constraints,
options->experimental_agc.Set(value);
else if (iter->key == MediaConstraintsInterface::kNoiseSuppression)
options->noise_suppression.Set(value);
else if (iter->key ==
MediaConstraintsInterface::kExperimentalNoiseSuppression)
options->experimental_ns.Set(value);
else if (iter->key == MediaConstraintsInterface::kHighpassFilter)
options->highpass_filter.Set(value);
else if (iter->key == MediaConstraintsInterface::kTypingNoiseDetection)

View File

@ -56,6 +56,8 @@ const char MediaConstraintsInterface::kExperimentalAutoGainControl[] =
"googAutoGainControl2";
const char MediaConstraintsInterface::kNoiseSuppression[] =
"googNoiseSuppression";
const char MediaConstraintsInterface::kExperimentalNoiseSuppression[] =
"googNoiseSuppression2";
const char MediaConstraintsInterface::kHighpassFilter[] =
"googHighpassFilter";
const char MediaConstraintsInterface::kTypingNoiseDetection[] =

View File

@ -79,6 +79,7 @@ class MediaConstraintsInterface {
static const char kAutoGainControl[]; // googAutoGainControl
static const char kExperimentalAutoGainControl[]; // googAutoGainControl2
static const char kNoiseSuppression[]; // googNoiseSuppression
static const char kExperimentalNoiseSuppression[]; // googNoiseSuppression2
static const char kHighpassFilter[]; // googHighpassFilter
static const char kTypingNoiseDetection[]; // googTypingNoiseDetection
static const char kAudioMirroring[]; // googAudioMirroring

View File

@ -114,7 +114,7 @@ void LocalAudioTrackHandler::OnEnabledChanged() {
// adapter owned by this class.
cricket::AudioRenderer* renderer = audio_track_->GetRenderer() ?
audio_track_->GetRenderer() : sink_adapter_.get();
ASSERT(renderer);
ASSERT(renderer != NULL);
provider_->SetAudioSend(ssrc(), audio_track_->enabled(), options, renderer);
}

View File

@ -1269,7 +1269,12 @@ TEST_F(JsepPeerConnectionP2PTestClient, GetBytesSentStats) {
}
// This test sets up a call between two parties with audio, video and data.
// TODO(jiayl): fix the flakiness on Windows and reenable. Issue 2891.
#if defined(WIN32)
TEST_F(JsepPeerConnectionP2PTestClient, DISABLED_LocalP2PTestDataChannel) {
#else
TEST_F(JsepPeerConnectionP2PTestClient, LocalP2PTestDataChannel) {
#endif
FakeConstraints setup_constraints;
setup_constraints.SetAllowRtpDataChannels();
ASSERT_TRUE(CreateTestClients(&setup_constraints, &setup_constraints));

View File

@ -83,6 +83,8 @@ const char StatsReport::kStatsValueNameFingerprintAlgorithm[] =
"googFingerprintAlgorithm";
const char StatsReport::kStatsValueNameFirsReceived[] = "googFirsReceived";
const char StatsReport::kStatsValueNameFirsSent[] = "googFirsSent";
const char StatsReport::kStatsValueNameFrameHeightInput[] =
"googFrameHeightInput";
const char StatsReport::kStatsValueNameFrameHeightReceived[] =
"googFrameHeightReceived";
const char StatsReport::kStatsValueNameFrameHeightSent[] =
@ -104,6 +106,8 @@ const char StatsReport::kStatsValueNameRenderDelayMs[] = "googRenderDelayMs";
const char StatsReport::kStatsValueNameFrameRateInput[] = "googFrameRateInput";
const char StatsReport::kStatsValueNameFrameRateSent[] = "googFrameRateSent";
const char StatsReport::kStatsValueNameFrameWidthInput[] =
"googFrameWidthInput";
const char StatsReport::kStatsValueNameFrameWidthReceived[] =
"googFrameWidthReceived";
const char StatsReport::kStatsValueNameFrameWidthSent[] = "googFrameWidthSent";
@ -117,6 +121,8 @@ const char StatsReport::kStatsValueNameLocalCertificateId[] =
"googLocalCertificateId";
const char StatsReport::kStatsValueNameNacksReceived[] = "googNacksReceived";
const char StatsReport::kStatsValueNameNacksSent[] = "googNacksSent";
const char StatsReport::kStatsValueNameNetEqExpandRate[] =
"googNetEqExpandRate";
const char StatsReport::kStatsValueNamePacketsReceived[] = "packetsReceived";
const char StatsReport::kStatsValueNamePacketsSent[] = "packetsSent";
const char StatsReport::kStatsValueNamePacketsLost[] = "packetsLost";
@ -215,6 +221,8 @@ void ExtractStats(const cricket::VoiceReceiverInfo& info, StatsReport* report) {
info.bytes_rcvd);
report->AddValue(StatsReport::kStatsValueNameJitterReceived,
info.jitter_ms);
report->AddValue(StatsReport::kStatsValueNameNetEqExpandRate,
talk_base::ToString<float>(info.expand_rate));
report->AddValue(StatsReport::kStatsValueNamePacketsReceived,
info.packets_rcvd);
report->AddValue(StatsReport::kStatsValueNamePacketsLost,
@ -295,10 +303,14 @@ void ExtractStats(const cricket::VideoSenderInfo& info, StatsReport* report) {
info.firs_rcvd);
report->AddValue(StatsReport::kStatsValueNameNacksReceived,
info.nacks_rcvd);
report->AddValue(StatsReport::kStatsValueNameFrameWidthInput,
info.input_frame_width);
report->AddValue(StatsReport::kStatsValueNameFrameHeightInput,
info.input_frame_height);
report->AddValue(StatsReport::kStatsValueNameFrameWidthSent,
info.frame_width);
info.send_frame_width);
report->AddValue(StatsReport::kStatsValueNameFrameHeightSent,
info.frame_height);
info.send_frame_height);
report->AddValue(StatsReport::kStatsValueNameFrameRateInput,
info.framerate_input);
report->AddValue(StatsReport::kStatsValueNameFrameRateSent,

View File

@ -143,6 +143,7 @@ class StatsReport {
static const char kStatsValueNameEchoReturnLossEnhancement[];
static const char kStatsValueNameFirsReceived[];
static const char kStatsValueNameFirsSent[];
static const char kStatsValueNameFrameHeightInput[];
static const char kStatsValueNameFrameHeightReceived[];
static const char kStatsValueNameFrameHeightSent[];
static const char kStatsValueNameFrameRateReceived[];
@ -157,11 +158,13 @@ class StatsReport {
static const char kStatsValueNameRenderDelayMs[];
static const char kStatsValueNameFrameRateInput[];
static const char kStatsValueNameFrameRateSent[];
static const char kStatsValueNameFrameWidthInput[];
static const char kStatsValueNameFrameWidthReceived[];
static const char kStatsValueNameFrameWidthSent[];
static const char kStatsValueNameJitterReceived[];
static const char kStatsValueNameNacksReceived[];
static const char kStatsValueNameNacksSent[];
static const char kStatsValueNameNetEqExpandRate[];
static const char kStatsValueNameRtt[];
static const char kStatsValueNameAvailableSendBandwidth[];
static const char kStatsValueNameAvailableReceiveBandwidth[];

View File

@ -0,0 +1,101 @@
/*
* libjingle
* Copyright 2014 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_ASYNCINVOKER_INL_H_
#define TALK_BASE_ASYNCINVOKER_INL_H_
#include "talk/base/criticalsection.h"
#include "talk/base/messagehandler.h"
#include "talk/base/sigslot.h"
#include "talk/base/thread.h"
namespace talk_base {
// Helper class for AsyncInvoker. Runs a functor on a message queue or thread
// and doesn't execute the callback when finished if the calling thread ends.
template <class ReturnT, class FunctorT>
class AsyncFunctorMessageHandler
: public FunctorMessageHandler<ReturnT, FunctorT>,
public sigslot::has_slots<> {
typedef AsyncFunctorMessageHandler<ReturnT, FunctorT> ThisT;
public:
explicit AsyncFunctorMessageHandler(const FunctorT& functor)
: FunctorMessageHandler<ReturnT, FunctorT>(functor),
thread_(Thread::Current()),
shutting_down_(false) {
thread_->SignalQueueDestroyed.connect(this, &ThisT::OnThreadDestroyed);
}
virtual ~AsyncFunctorMessageHandler() {
CritScope cs(&running_crit_);
shutting_down_ = true;
}
virtual void OnMessage(Message* msg) {
CritScope cs(&running_crit_);
if (!shutting_down_) {
FunctorMessageHandler<ReturnT, FunctorT>::OnMessage(msg);
}
}
// Returns the thread that initiated the async call.
Thread* thread() const { return thread_; }
// Wraps a callback so that it won't execute if |thread_| goes away.
void WrapCallback(Callback0<void> cb) {
this->SetCallback(
Callback0<void>(Bind(&ThisT::MaybeRunCallback, this, cb)));
}
private:
void OnThreadDestroyed() {
CritScope cs(&thread_crit_);
thread_ = NULL;
this->SetCallback(Callback0<void>()); // Clear out the callback.
}
void MaybeRunCallback(Callback0<void> cb) {
#ifdef _DEBUG
ASSERT(running_crit_.CurrentThreadIsOwner());
#endif
CritScope cs(&thread_crit_);
if (thread_ && !shutting_down_) {
cb();
}
}
FunctorT functor_;
Thread* thread_;
CriticalSection thread_crit_;
CriticalSection running_crit_;
bool shutting_down_;
};
} // namespace talk_base
#endif // TALK_BASE_ASYNCINVOKER_INL_H_

78
talk/base/asyncinvoker.cc Normal file
View File

@ -0,0 +1,78 @@
/*
* libjingle
* Copyright 2014 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/asyncinvoker.h"
namespace talk_base {
// Synchronously execute all outstanding calls we own pending
// on |thread|. Optionally filter by message id.
void AsyncInvoker::Flush(Thread* thread, uint32 id /*= MQID_ANY*/) {
// Run this on |thread| to reduce the number of context switches.
if (Thread::Current() != thread) {
thread->Invoke<void>(Bind(&AsyncInvoker::Flush, this, thread, id));
return;
}
// Make a copy of handlers_, since it'll be modified by
// callbacks to RemoveHandler when each is done executing.
crit_.Enter();
std::vector<MessageHandler*> handlers(handlers_.collection());
crit_.Leave();
MessageList removed;
for (size_t i = 0; i < handlers.size(); ++i) {
removed.clear();
thread->Clear(handlers[i], id, &removed);
if (!removed.empty()) {
// Since each message gets its own handler with AsyncInvoker,
// we expect a maximum of one removed.
ASSERT(removed.size() == 1);
// This handler was pending on this thread, so run it now.
const Message& msg = removed.front();
thread->Send(msg.phandler,
msg.message_id,
msg.pdata);
}
}
}
void AsyncInvoker::InvokeHandler(Thread* thread, MessageHandler* handler,
uint32 id) {
{
CritScope cs(&crit_);
handlers_.PushBack(handler);
}
thread->Post(handler, id);
}
void AsyncInvoker::RemoveHandler(MessageHandler* handler) {
CritScope cs(&crit_);
handlers_.Remove(handler);
delete handler;
}
} // namespace talk_base

167
talk/base/asyncinvoker.h Normal file
View File

@ -0,0 +1,167 @@
/*
* libjingle
* Copyright 2014 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_ASYNCINVOKER_H_
#define TALK_BASE_ASYNCINVOKER_H_
#include "talk/base/asyncinvoker-inl.h"
#include "talk/base/bind.h"
#include "talk/base/scopedptrcollection.h"
#include "talk/base/thread.h"
namespace talk_base {
// Invokes function objects (aka functors) asynchronously on a Thread, and
// owns the lifetime of calls (ie, when this object is destroyed, calls in
// flight are cancelled). AsyncInvoker can optionally execute a user-specified
// function when the asynchronous call is complete, or operates in
// fire-and-forget mode otherwise.
//
// AsyncInvoker does not own the thread it calls functors on.
//
// A note about async calls and object lifetimes: users should
// be mindful of object lifetimes when calling functions asynchronously and
// ensure objects used by the function _cannot_ be deleted between the
// invocation and execution of the functor. AsyncInvoker is designed to
// help: any calls in flight will be cancelled when the AsyncInvoker used to
// make the call is destructed, and any calls executing will be allowed to
// complete before AsyncInvoker destructs.
//
// The easiest way to ensure lifetimes are handled correctly is to create a
// class that owns the Thread and AsyncInvoker objects, and then call its
// methods asynchronously as needed.
//
// Example:
// class MyClass {
// public:
// void FireAsyncTaskWithResult(Thread* thread, int x) {
// // Specify a callback to get the result upon completion.
// invoker_.AsyncInvoke<int>(
// thread, Bind(&MyClass::AsyncTaskWithResult, this, x),
// &MyClass::OnTaskComplete, this);
// }
// void FireAnotherAsyncTask(Thread* thread) {
// // No callback specified means fire-and-forget.
// invoker_.AsyncInvoke<void>(
// thread, Bind(&MyClass::AnotherAsyncTask, this));
//
// private:
// int AsyncTaskWithResult(int x) {
// // Some long running process...
// return x * x;
// }
// void AnotherAsyncTask() {
// // Some other long running process...
// }
// void OnTaskComplete(int result) { result_ = result; }
//
// AsyncInvoker invoker_;
// int result_;
// };
class AsyncInvoker {
public:
// Call |functor| asynchronously on |thread|, with no callback upon
// completion. Returns immediately.
template <class ReturnT, class FunctorT>
void AsyncInvoke(Thread* thread,
const FunctorT& functor,
uint32 id = 0) {
FunctorMessageHandler<ReturnT, FunctorT>* handler =
new FunctorMessageHandler<ReturnT, FunctorT>(functor);
handler->SetCallback(Bind(&AsyncInvoker::RemoveHandler, this, handler));
InvokeHandler(thread, handler, id);
}
// Call |functor| asynchronously on |thread|, calling |callback| when done.
template <class ReturnT, class FunctorT, class HostT>
void AsyncInvoke(Thread* thread,
const FunctorT& functor,
void (HostT::*callback)(ReturnT),
HostT* callback_host,
uint32 id = 0) {
AsyncFunctorMessageHandler<ReturnT, FunctorT>* handler =
new AsyncFunctorMessageHandler<ReturnT, FunctorT>(functor);
handler->WrapCallback(
Bind(&AsyncInvoker::OnAsyncCallCompleted<ReturnT, FunctorT, HostT>,
this, handler, callback, callback_host));
InvokeHandler(thread, handler, id);
}
// Call |functor| asynchronously on |thread|, calling |callback| when done.
// Overloaded for void return.
template <class ReturnT, class FunctorT, class HostT>
void AsyncInvoke(Thread* thread,
const FunctorT& functor,
void (HostT::*callback)(),
HostT* callback_host,
uint32 id = 0) {
AsyncFunctorMessageHandler<void, FunctorT>* handler =
new AsyncFunctorMessageHandler<ReturnT, FunctorT>(functor);
handler->WrapCallback(
Bind(&AsyncInvoker::OnAsyncVoidCallCompleted<FunctorT, HostT>,
this, handler, callback, callback_host));
InvokeHandler(thread, handler, id);
}
// Synchronously execute on |thread| all outstanding calls we own
// that are pending on |thread|, and wait for calls to complete
// before returning. Optionally filter by message id.
// The destructor will not wait for outstanding calls, so if that
// behavior is desired, call Flush() before destroying this object.
void Flush(Thread* thread, uint32 id = MQID_ANY);
private:
void InvokeHandler(Thread* thread, MessageHandler* handler, uint32 id);
void RemoveHandler(MessageHandler* handler);
template <class ReturnT, class FunctorT, class HostT>
void OnAsyncCallCompleted(
AsyncFunctorMessageHandler<ReturnT, FunctorT>* handler,
void (HostT::*callback)(ReturnT),
HostT* callback_host) {
AsyncInvoke<void>(handler->thread(),
Bind(callback, callback_host, handler->result()));
RemoveHandler(handler);
}
template <class FunctorT, class HostT>
void OnAsyncVoidCallCompleted(
AsyncFunctorMessageHandler<void, FunctorT>* handler,
void (HostT::*callback)(),
HostT* callback_host) {
AsyncInvoke<void>(handler->thread(), Bind(callback, callback_host));
RemoveHandler(handler);
}
CriticalSection crit_;
ScopedPtrCollection<MessageHandler> handlers_;
};
} // namespace talk_base
#endif // TALK_BASE_ASYNCINVOKER_H_

View File

@ -84,6 +84,18 @@ class MethodFunctor0 {
ObjectT* object_;
};
template <class FunctorT, class R>
class Functor0 {
public:
explicit Functor0(const FunctorT& functor)
: functor_(functor) {}
R operator()() const {
return functor_(); }
private:
FunctorT functor_;
};
#define FP_T(x) R (ObjectT::*x)()
template <class ObjectT, class R>
@ -103,6 +115,16 @@ Bind(FP_T(method), const ObjectT* object) {
method, object);
}
#undef FP_T
#define FP_T(x) R (*x)()
template <class R>
Functor0<FP_T(NONAME), R>
Bind(FP_T(function)) {
return Functor0<FP_T(NONAME), R>(
function);
}
#undef FP_T
template <class ObjectT, class MethodT, class R,
@ -121,6 +143,21 @@ class MethodFunctor1 {
P1 p1_;
};
template <class FunctorT, class R,
class P1>
class Functor1 {
public:
Functor1(const FunctorT& functor, P1 p1)
: functor_(functor),
p1_(p1) {}
R operator()() const {
return functor_(p1_); }
private:
FunctorT functor_;
P1 p1_;
};
#define FP_T(x) R (ObjectT::*x)(P1)
template <class ObjectT, class R,
@ -144,6 +181,18 @@ Bind(FP_T(method), const ObjectT* object,
method, object, p1);
}
#undef FP_T
#define FP_T(x) R (*x)(P1)
template <class R,
class P1>
Functor1<FP_T(NONAME), R, P1>
Bind(FP_T(function),
typename detail::identity<P1>::type p1) {
return Functor1<FP_T(NONAME), R, P1>(
function, p1);
}
#undef FP_T
template <class ObjectT, class MethodT, class R,
@ -166,6 +215,24 @@ class MethodFunctor2 {
P2 p2_;
};
template <class FunctorT, class R,
class P1,
class P2>
class Functor2 {
public:
Functor2(const FunctorT& functor, P1 p1, P2 p2)
: functor_(functor),
p1_(p1),
p2_(p2) {}
R operator()() const {
return functor_(p1_, p2_); }
private:
FunctorT functor_;
P1 p1_;
P2 p2_;
};
#define FP_T(x) R (ObjectT::*x)(P1, P2)
template <class ObjectT, class R,
@ -193,6 +260,20 @@ Bind(FP_T(method), const ObjectT* object,
method, object, p1, p2);
}
#undef FP_T
#define FP_T(x) R (*x)(P1, P2)
template <class R,
class P1,
class P2>
Functor2<FP_T(NONAME), R, P1, P2>
Bind(FP_T(function),
typename detail::identity<P1>::type p1,
typename detail::identity<P2>::type p2) {
return Functor2<FP_T(NONAME), R, P1, P2>(
function, p1, p2);
}
#undef FP_T
template <class ObjectT, class MethodT, class R,
@ -219,6 +300,27 @@ class MethodFunctor3 {
P3 p3_;
};
template <class FunctorT, class R,
class P1,
class P2,
class P3>
class Functor3 {
public:
Functor3(const FunctorT& functor, P1 p1, P2 p2, P3 p3)
: functor_(functor),
p1_(p1),
p2_(p2),
p3_(p3) {}
R operator()() const {
return functor_(p1_, p2_, p3_); }
private:
FunctorT functor_;
P1 p1_;
P2 p2_;
P3 p3_;
};
#define FP_T(x) R (ObjectT::*x)(P1, P2, P3)
template <class ObjectT, class R,
@ -250,6 +352,22 @@ Bind(FP_T(method), const ObjectT* object,
method, object, p1, p2, p3);
}
#undef FP_T
#define FP_T(x) R (*x)(P1, P2, P3)
template <class R,
class P1,
class P2,
class P3>
Functor3<FP_T(NONAME), R, P1, P2, P3>
Bind(FP_T(function),
typename detail::identity<P1>::type p1,
typename detail::identity<P2>::type p2,
typename detail::identity<P3>::type p3) {
return Functor3<FP_T(NONAME), R, P1, P2, P3>(
function, p1, p2, p3);
}
#undef FP_T
template <class ObjectT, class MethodT, class R,
@ -280,6 +398,30 @@ class MethodFunctor4 {
P4 p4_;
};
template <class FunctorT, class R,
class P1,
class P2,
class P3,
class P4>
class Functor4 {
public:
Functor4(const FunctorT& functor, P1 p1, P2 p2, P3 p3, P4 p4)
: functor_(functor),
p1_(p1),
p2_(p2),
p3_(p3),
p4_(p4) {}
R operator()() const {
return functor_(p1_, p2_, p3_, p4_); }
private:
FunctorT functor_;
P1 p1_;
P2 p2_;
P3 p3_;
P4 p4_;
};
#define FP_T(x) R (ObjectT::*x)(P1, P2, P3, P4)
template <class ObjectT, class R,
@ -315,6 +457,24 @@ Bind(FP_T(method), const ObjectT* object,
method, object, p1, p2, p3, p4);
}
#undef FP_T
#define FP_T(x) R (*x)(P1, P2, P3, P4)
template <class R,
class P1,
class P2,
class P3,
class P4>
Functor4<FP_T(NONAME), R, P1, P2, P3, P4>
Bind(FP_T(function),
typename detail::identity<P1>::type p1,
typename detail::identity<P2>::type p2,
typename detail::identity<P3>::type p3,
typename detail::identity<P4>::type p4) {
return Functor4<FP_T(NONAME), R, P1, P2, P3, P4>(
function, p1, p2, p3, p4);
}
#undef FP_T
template <class ObjectT, class MethodT, class R,
@ -349,6 +509,33 @@ class MethodFunctor5 {
P5 p5_;
};
template <class FunctorT, class R,
class P1,
class P2,
class P3,
class P4,
class P5>
class Functor5 {
public:
Functor5(const FunctorT& functor, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5)
: functor_(functor),
p1_(p1),
p2_(p2),
p3_(p3),
p4_(p4),
p5_(p5) {}
R operator()() const {
return functor_(p1_, p2_, p3_, p4_, p5_); }
private:
FunctorT functor_;
P1 p1_;
P2 p2_;
P3 p3_;
P4 p4_;
P5 p5_;
};
#define FP_T(x) R (ObjectT::*x)(P1, P2, P3, P4, P5)
template <class ObjectT, class R,
@ -388,6 +575,26 @@ Bind(FP_T(method), const ObjectT* object,
method, object, p1, p2, p3, p4, p5);
}
#undef FP_T
#define FP_T(x) R (*x)(P1, P2, P3, P4, P5)
template <class R,
class P1,
class P2,
class P3,
class P4,
class P5>
Functor5<FP_T(NONAME), R, P1, P2, P3, P4, P5>
Bind(FP_T(function),
typename detail::identity<P1>::type p1,
typename detail::identity<P2>::type p2,
typename detail::identity<P3>::type p3,
typename detail::identity<P4>::type p4,
typename detail::identity<P5>::type p5) {
return Functor5<FP_T(NONAME), R, P1, P2, P3, P4, P5>(
function, p1, p2, p3, p4, p5);
}
#undef FP_T
} // namespace talk_base

View File

@ -91,6 +91,24 @@ class MethodFunctor$i {
};
template <class FunctorT, class R$for j [[,
class P$j]]>
class Functor$i {
public:
$if i == 0 [[explicit ]]
Functor$i(const FunctorT& functor$for j [[, P$j p$j]])
: functor_(functor)$for j [[,
p$(j)_(p$j)]] {}
R operator()() const {
return functor_($for j , [[p$(j)_]]); }
private:
FunctorT functor_;$for j [[
P$j p$(j)_;]]
};
#define FP_T(x) R (ObjectT::*x)($for j , [[P$j]])
template <class ObjectT, class R$for j [[,
@ -114,6 +132,18 @@ Bind(FP_T(method), const ObjectT* object$for j [[,
method, object$for j [[, p$j]]);
}
#undef FP_T
#define FP_T(x) R (*x)($for j , [[P$j]])
template <class R$for j [[,
class P$j]]>
Functor$i<FP_T(NONAME), R$for j [[, P$j]]>
Bind(FP_T(function)$for j [[,
typename detail::identity<P$j>::type p$j]]) {
return Functor$i<FP_T(NONAME), R$for j [[, P$j]]>(
function$for j [[, p$j]]);
}
#undef FP_T
]]

View File

@ -43,6 +43,10 @@ struct MethodBindTester {
mutable int call_count;
};
int Return42() { return 42; }
int Negate(int a) { return -a; }
int Multiply(int a, int b) { return a * b; }
} // namespace
TEST(BindTest, BindToMethod) {
@ -71,4 +75,10 @@ TEST(BindTest, BindToMethod) {
EXPECT_EQ(8, object.call_count);
}
TEST(BindTest, BindToFunction) {
EXPECT_EQ(42, Bind(&Return42)());
EXPECT_EQ(3, Bind(&Negate, -3)());
EXPECT_EQ(56, Bind(&Multiply, 8, 7)());
}
} // namespace talk_base

291
talk/base/callback.h Normal file
View File

@ -0,0 +1,291 @@
// This file was GENERATED by command:
// pump.py callback.h.pump
// DO NOT EDIT BY HAND!!!
/*
* libjingle
* Copyright 2012 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.
*/
// To generate callback.h from callback.h.pump, execute:
// /home/build/google3/third_party/gtest/scripts/pump.py callback.h.pump
// Callbacks are callable object containers. They can hold a function pointer
// or a function object and behave like a value type. Internally, data is
// reference-counted, making copies and pass-by-value inexpensive.
//
// Callbacks are typed using template arguments. The format is:
// CallbackN<ReturnType, ParamType1, ..., ParamTypeN>
// where N is the number of arguments supplied to the callable object.
// Callbacks are invoked using operator(), just like a function or a function
// object. Default-constructed callbacks are "empty," and executing an empty
// callback does nothing. A callback can be made empty by assigning it from
// a default-constructed callback.
//
// Callbacks are similar in purpose to std::function (which isn't available on
// all platforms we support) and a lightweight alternative to sigslots. Since
// they effectively hide the type of the object they call, they're useful in
// breaking dependencies between objects that need to interact with one another.
// Notably, they can hold the results of Bind(), std::bind*, etc, without
// needing
// to know the resulting object type of those calls.
//
// Sigslots, on the other hand, provide a fuller feature set, such as multiple
// subscriptions to a signal, optional thread-safety, and lifetime tracking of
// slots. When these features are needed, choose sigslots.
//
// Example:
// int sqr(int x) { return x * x; }
// struct AddK {
// int k;
// int operator()(int x) const { return x + k; }
// } add_k = {5};
//
// Callback1<int, int> my_callback;
// cout << my_callback.empty() << endl; // true
//
// my_callback = Callback1<int, int>(&sqr);
// cout << my_callback.empty() << endl; // false
// cout << my_callback(3) << endl; // 9
//
// my_callback = Callback1<int, int>(add_k);
// cout << my_callback(10) << endl; // 15
//
// my_callback = Callback1<int, int>();
// cout << my_callback.empty() << endl; // true
#ifndef TALK_BASE_CALLBACK_H_
#define TALK_BASE_CALLBACK_H_
#include "talk/base/logging.h"
#include "talk/base/refcount.h"
#include "talk/base/scoped_ref_ptr.h"
namespace talk_base {
template <class R>
class Callback0 {
public:
// Default copy operations are appropriate for this class.
Callback0() {}
template <class T> Callback0(const T& functor)
: helper_(new RefCountedObject< HelperImpl<T> >(functor)) {}
R operator()() {
if (empty()) {
LOG_F(LS_WARNING) << "Tried to execute an empty callback.";
return R();
}
return helper_->Run();
}
bool empty() const { return !helper_; }
private:
struct Helper : RefCountInterface {
virtual ~Helper() {}
virtual R Run() = 0;
};
template <class T> struct HelperImpl : Helper {
explicit HelperImpl(const T& functor) : functor_(functor) {}
virtual R Run() {
return functor_();
}
T functor_;
};
scoped_refptr<Helper> helper_;
};
template <class R,
class P1>
class Callback1 {
public:
// Default copy operations are appropriate for this class.
Callback1() {}
template <class T> Callback1(const T& functor)
: helper_(new RefCountedObject< HelperImpl<T> >(functor)) {}
R operator()(P1 p1) {
if (empty()) {
LOG_F(LS_WARNING) << "Tried to execute an empty callback.";
return R();
}
return helper_->Run(p1);
}
bool empty() const { return !helper_; }
private:
struct Helper : RefCountInterface {
virtual ~Helper() {}
virtual R Run(P1 p1) = 0;
};
template <class T> struct HelperImpl : Helper {
explicit HelperImpl(const T& functor) : functor_(functor) {}
virtual R Run(P1 p1) {
return functor_(p1);
}
T functor_;
};
scoped_refptr<Helper> helper_;
};
template <class R,
class P1,
class P2>
class Callback2 {
public:
// Default copy operations are appropriate for this class.
Callback2() {}
template <class T> Callback2(const T& functor)
: helper_(new RefCountedObject< HelperImpl<T> >(functor)) {}
R operator()(P1 p1, P2 p2) {
if (empty()) {
LOG_F(LS_WARNING) << "Tried to execute an empty callback.";
return R();
}
return helper_->Run(p1, p2);
}
bool empty() const { return !helper_; }
private:
struct Helper : RefCountInterface {
virtual ~Helper() {}
virtual R Run(P1 p1, P2 p2) = 0;
};
template <class T> struct HelperImpl : Helper {
explicit HelperImpl(const T& functor) : functor_(functor) {}
virtual R Run(P1 p1, P2 p2) {
return functor_(p1, p2);
}
T functor_;
};
scoped_refptr<Helper> helper_;
};
template <class R,
class P1,
class P2,
class P3>
class Callback3 {
public:
// Default copy operations are appropriate for this class.
Callback3() {}
template <class T> Callback3(const T& functor)
: helper_(new RefCountedObject< HelperImpl<T> >(functor)) {}
R operator()(P1 p1, P2 p2, P3 p3) {
if (empty()) {
LOG_F(LS_WARNING) << "Tried to execute an empty callback.";
return R();
}
return helper_->Run(p1, p2, p3);
}
bool empty() const { return !helper_; }
private:
struct Helper : RefCountInterface {
virtual ~Helper() {}
virtual R Run(P1 p1, P2 p2, P3 p3) = 0;
};
template <class T> struct HelperImpl : Helper {
explicit HelperImpl(const T& functor) : functor_(functor) {}
virtual R Run(P1 p1, P2 p2, P3 p3) {
return functor_(p1, p2, p3);
}
T functor_;
};
scoped_refptr<Helper> helper_;
};
template <class R,
class P1,
class P2,
class P3,
class P4>
class Callback4 {
public:
// Default copy operations are appropriate for this class.
Callback4() {}
template <class T> Callback4(const T& functor)
: helper_(new RefCountedObject< HelperImpl<T> >(functor)) {}
R operator()(P1 p1, P2 p2, P3 p3, P4 p4) {
if (empty()) {
LOG_F(LS_WARNING) << "Tried to execute an empty callback.";
return R();
}
return helper_->Run(p1, p2, p3, p4);
}
bool empty() const { return !helper_; }
private:
struct Helper : RefCountInterface {
virtual ~Helper() {}
virtual R Run(P1 p1, P2 p2, P3 p3, P4 p4) = 0;
};
template <class T> struct HelperImpl : Helper {
explicit HelperImpl(const T& functor) : functor_(functor) {}
virtual R Run(P1 p1, P2 p2, P3 p3, P4 p4) {
return functor_(p1, p2, p3, p4);
}
T functor_;
};
scoped_refptr<Helper> helper_;
};
template <class R,
class P1,
class P2,
class P3,
class P4,
class P5>
class Callback5 {
public:
// Default copy operations are appropriate for this class.
Callback5() {}
template <class T> Callback5(const T& functor)
: helper_(new RefCountedObject< HelperImpl<T> >(functor)) {}
R operator()(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) {
if (empty()) {
LOG_F(LS_WARNING) << "Tried to execute an empty callback.";
return R();
}
return helper_->Run(p1, p2, p3, p4, p5);
}
bool empty() const { return !helper_; }
private:
struct Helper : RefCountInterface {
virtual ~Helper() {}
virtual R Run(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) = 0;
};
template <class T> struct HelperImpl : Helper {
explicit HelperImpl(const T& functor) : functor_(functor) {}
virtual R Run(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) {
return functor_(p1, p2, p3, p4, p5);
}
T functor_;
};
scoped_refptr<Helper> helper_;
};
} // namespace talk_base
#endif // TALK_BASE_CALLBACK_H_

123
talk/base/callback.h.pump Normal file
View File

@ -0,0 +1,123 @@
/*
* libjingle
* Copyright 2012 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.
*/
// To generate callback.h from callback.h.pump, execute:
// /home/build/google3/third_party/gtest/scripts/pump.py callback.h.pump
// Callbacks are callable object containers. They can hold a function pointer
// or a function object and behave like a value type. Internally, data is
// reference-counted, making copies and pass-by-value inexpensive.
//
// Callbacks are typed using template arguments. The format is:
// CallbackN<ReturnType, ParamType1, ..., ParamTypeN>
// where N is the number of arguments supplied to the callable object.
// Callbacks are invoked using operator(), just like a function or a function
// object. Default-constructed callbacks are "empty," and executing an empty
// callback does nothing. A callback can be made empty by assigning it from
// a default-constructed callback.
//
// Callbacks are similar in purpose to std::function (which isn't available on
// all platforms we support) and a lightweight alternative to sigslots. Since
// they effectively hide the type of the object they call, they're useful in
// breaking dependencies between objects that need to interact with one another.
// Notably, they can hold the results of Bind(), std::bind*, etc, without needing
// to know the resulting object type of those calls.
//
// Sigslots, on the other hand, provide a fuller feature set, such as multiple
// subscriptions to a signal, optional thread-safety, and lifetime tracking of
// slots. When these features are needed, choose sigslots.
//
// Example:
// int sqr(int x) { return x * x; }
// struct AddK {
// int k;
// int operator()(int x) const { return x + k; }
// } add_k = {5};
//
// Callback1<int, int> my_callback;
// cout << my_callback.empty() << endl; // true
//
// my_callback = Callback1<int, int>(&sqr);
// cout << my_callback.empty() << endl; // false
// cout << my_callback(3) << endl; // 9
//
// my_callback = Callback1<int, int>(add_k);
// cout << my_callback(10) << endl; // 15
//
// my_callback = Callback1<int, int>();
// cout << my_callback.empty() << endl; // true
#ifndef TALK_BASE_CALLBACK_H_
#define TALK_BASE_CALLBACK_H_
#include "talk/base/logging.h"
#include "talk/base/refcount.h"
#include "talk/base/scoped_ref_ptr.h"
namespace talk_base {
$var n = 5
$range i 0..n
$for i [[
$range j 1..i
template <class R$for j [[,
class P$j]]>
class Callback$i {
public:
// Default copy operations are appropriate for this class.
Callback$i() {}
template <class T> Callback$i(const T& functor)
: helper_(new RefCountedObject< HelperImpl<T> >(functor)) {}
R operator()($for j , [[P$j p$j]]) {
if (empty()) {
LOG_F(LS_WARNING) << "Tried to execute an empty callback.";
return R();
}
return helper_->Run($for j , [[p$j]]);
}
bool empty() const { return !helper_; }
private:
struct Helper : RefCountInterface {
virtual ~Helper() {}
virtual R Run($for j , [[P$j p$j]]) = 0;
};
template <class T> struct HelperImpl : Helper {
explicit HelperImpl(const T& functor) : functor_(functor) {}
virtual R Run($for j , [[P$j p$j]]) {
return functor_($for j , [[p$j]]);
}
T functor_;
};
scoped_refptr<Helper> helper_;
};
]]
} // namespace talk_base
#endif // TALK_BASE_CALLBACK_H_

View File

@ -0,0 +1,98 @@
/*
* 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/base/bind.h"
#include "talk/base/callback.h"
#include "talk/base/gunit.h"
namespace talk_base {
namespace {
void f() {}
int g() { return 42; }
int h(int x) { return x * x; }
void i(int& x) { x *= x; } // NOLINT: Testing refs
struct BindTester {
int a() { return 24; }
int b(int x) const { return x * x; }
};
} // namespace
TEST(CallbackTest, VoidReturn) {
Callback0<void> cb;
EXPECT_TRUE(cb.empty());
cb(); // Executing an empty callback should not crash.
cb = Callback0<void>(&f);
EXPECT_FALSE(cb.empty());
cb();
}
TEST(CallbackTest, IntReturn) {
Callback0<int> cb;
EXPECT_TRUE(cb.empty());
cb = Callback0<int>(&g);
EXPECT_FALSE(cb.empty());
EXPECT_EQ(42, cb());
EXPECT_EQ(42, cb());
}
TEST(CallbackTest, OneParam) {
Callback1<int, int> cb1(&h);
EXPECT_FALSE(cb1.empty());
EXPECT_EQ(9, cb1(-3));
EXPECT_EQ(100, cb1(10));
// Try clearing a callback.
cb1 = Callback1<int, int>();
EXPECT_TRUE(cb1.empty());
// Try a callback with a ref parameter.
Callback1<void, int&> cb2(&i);
int x = 3;
cb2(x);
EXPECT_EQ(9, x);
cb2(x);
EXPECT_EQ(81, x);
}
TEST(CallbackTest, WithBind) {
BindTester t;
Callback0<int> cb1 = Bind(&BindTester::a, &t);
EXPECT_EQ(24, cb1());
EXPECT_EQ(24, cb1());
cb1 = Bind(&BindTester::b, &t, 10);
EXPECT_EQ(100, cb1());
EXPECT_EQ(100, cb1());
cb1 = Bind(&BindTester::b, &t, 5);
EXPECT_EQ(25, cb1());
EXPECT_EQ(25, cb1());
}
} // namespace talk_base

View File

@ -28,6 +28,7 @@
#ifndef TALK_BASE_MESSAGEHANDLER_H_
#define TALK_BASE_MESSAGEHANDLER_H_
#include "talk/base/callback.h"
#include "talk/base/constructormagic.h"
namespace talk_base {
@ -38,16 +39,52 @@ struct Message;
class MessageHandler {
public:
virtual ~MessageHandler();
virtual void OnMessage(Message* msg) = 0;
protected:
MessageHandler() {}
virtual ~MessageHandler();
private:
DISALLOW_COPY_AND_ASSIGN(MessageHandler);
};
// Helper class to facilitate executing a functor on a thread.
template <class ReturnT, class FunctorT>
class FunctorMessageHandler : public MessageHandler {
public:
explicit FunctorMessageHandler(const FunctorT& functor)
: functor_(functor) {}
virtual void OnMessage(Message* msg) {
result_ = functor_();
if (!callback_.empty()) callback_();
}
const ReturnT& result() const { return result_; }
void SetCallback(const Callback0<void>& callback) { callback_ = callback; }
private:
FunctorT functor_;
ReturnT result_;
Callback0<void> callback_;
};
// Specialization for ReturnT of void.
template <class FunctorT>
class FunctorMessageHandler<void, FunctorT> : public MessageHandler {
public:
explicit FunctorMessageHandler(const FunctorT& functor)
: functor_(functor) {}
virtual void OnMessage(Message* msg) {
functor_();
if (!callback_.empty()) callback_();
}
void result() const {}
void SetCallback(const Callback0<void>& callback) { callback_ = callback; }
private:
FunctorT functor_;
Callback0<void> callback_;
};
} // namespace talk_base
#endif // TALK_BASE_MESSAGEHANDLER_H_

View File

@ -0,0 +1,77 @@
/*
* libjingle
* Copyright 2014 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.
*/
// Stores a collection of pointers that are deleted when the container is
// destructed.
#ifndef TALK_BASE_SCOPEDPTRCOLLECTION_H_
#define TALK_BASE_SCOPEDPTRCOLLECTION_H_
#include <algorithm>
#include <vector>
#include "talk/base/basictypes.h"
#include "talk/base/constructormagic.h"
namespace talk_base {
template<class T>
class ScopedPtrCollection {
public:
typedef std::vector<T*> VectorT;
ScopedPtrCollection() { }
~ScopedPtrCollection() {
for (typename VectorT::iterator it = collection_.begin();
it != collection_.end(); ++it) {
delete *it;
}
}
const VectorT& collection() const { return collection_; }
void Reserve(size_t size) {
collection_.reserve(size);
}
void PushBack(T* t) {
collection_.push_back(t);
}
// Remove |t| from the collection without deleting it.
void Remove(T* t) {
collection_.erase(std::remove(collection_.begin(), collection_.end(), t),
collection_.end());
}
private:
VectorT collection_;
DISALLOW_COPY_AND_ASSIGN(ScopedPtrCollection);
};
} // namespace talk_base
#endif // TALK_BASE_SCOPEDPTRCOLLECTION_H_

View File

@ -0,0 +1,90 @@
/*
* libjingle
* Copyright 2014 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/scopedptrcollection.h"
#include "talk/base/gunit.h"
namespace talk_base {
namespace {
class InstanceCounter {
public:
explicit InstanceCounter(int* num_instances)
: num_instances_(num_instances) {
++(*num_instances_);
}
~InstanceCounter() {
--(*num_instances_);
}
private:
int* num_instances_;
DISALLOW_COPY_AND_ASSIGN(InstanceCounter);
};
} // namespace
class ScopedPtrCollectionTest : public testing::Test {
protected:
ScopedPtrCollectionTest()
: num_instances_(0),
collection_(new ScopedPtrCollection<InstanceCounter>()) {
}
int num_instances_;
scoped_ptr<ScopedPtrCollection<InstanceCounter> > collection_;
};
TEST_F(ScopedPtrCollectionTest, PushBack) {
EXPECT_EQ(0u, collection_->collection().size());
EXPECT_EQ(0, num_instances_);
const int kNum = 100;
for (int i = 0; i < kNum; ++i) {
collection_->PushBack(new InstanceCounter(&num_instances_));
}
EXPECT_EQ(static_cast<size_t>(kNum), collection_->collection().size());
EXPECT_EQ(kNum, num_instances_);
collection_.reset();
EXPECT_EQ(0, num_instances_);
}
TEST_F(ScopedPtrCollectionTest, Remove) {
InstanceCounter* ic = new InstanceCounter(&num_instances_);
collection_->PushBack(ic);
EXPECT_EQ(1u, collection_->collection().size());
collection_->Remove(ic);
EXPECT_EQ(1, num_instances_);
collection_.reset();
EXPECT_EQ(1, num_instances_);
delete ic;
EXPECT_EQ(0, num_instances_);
}
} // namespace talk_base

View File

@ -223,33 +223,6 @@ class Thread : public MessageQueue {
void Join();
private:
// Helper class to facilitate executing a functor on a thread.
template <class ReturnT, class FunctorT>
class FunctorMessageHandler : public MessageHandler {
public:
explicit FunctorMessageHandler(const FunctorT& functor)
: functor_(functor) {}
virtual void OnMessage(Message* msg) {
result_ = functor_();
}
const ReturnT& result() const { return result_; }
private:
FunctorT functor_;
ReturnT result_;
};
// Specialization for ReturnT of void.
template <class FunctorT>
class FunctorMessageHandler<void, FunctorT> : public MessageHandler {
public:
explicit FunctorMessageHandler(const FunctorT& functor)
: functor_(functor) {}
virtual void OnMessage(Message* msg) { functor_(); }
void result() const {}
private:
FunctorT functor_;
};
static void *PreRun(void *pv);
// ThreadManager calls this instead WrapCurrent() because

View File

@ -25,6 +25,7 @@
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "talk/base/asyncinvoker.h"
#include "talk/base/asyncudpsocket.h"
#include "talk/base/event.h"
#include "talk/base/gunit.h"
@ -150,16 +151,22 @@ class SignalWhenDestroyedThread : public Thread {
};
// Function objects to test Thread::Invoke.
struct Functor1 {
struct FunctorA {
int operator()() { return 42; }
};
class Functor2 {
class FunctorB {
public:
explicit Functor2(bool* flag) : flag_(flag) {}
explicit FunctorB(bool* flag) : flag_(flag) {}
void operator()() { if (flag_) *flag_ = true; }
private:
bool* flag_;
};
struct FunctorC {
int operator()() {
Thread::Current()->ProcessMessages(50);
return 24;
}
};
// See: https://code.google.com/p/webrtc/issues/detail?id=2409
TEST(ThreadTest, DISABLED_Main) {
@ -289,9 +296,9 @@ TEST(ThreadTest, Invoke) {
Thread thread;
thread.Start();
// Try calling functors.
EXPECT_EQ(42, thread.Invoke<int>(Functor1()));
EXPECT_EQ(42, thread.Invoke<int>(FunctorA()));
bool called = false;
Functor2 f2(&called);
FunctorB f2(&called);
thread.Invoke<void>(f2);
EXPECT_TRUE(called);
// Try calling bare functions.
@ -303,6 +310,152 @@ TEST(ThreadTest, Invoke) {
thread.Invoke<void>(&LocalFuncs::Func2);
}
class AsyncInvokeTest : public testing::Test {
public:
void IntCallback(int value) {
EXPECT_EQ(expected_thread_, Thread::Current());
int_value_ = value;
}
void AsyncInvokeIntCallback(AsyncInvoker* invoker, Thread* thread) {
expected_thread_ = thread;
invoker->AsyncInvoke(thread, FunctorC(),
&AsyncInvokeTest::IntCallback,
static_cast<AsyncInvokeTest*>(this));
invoke_started_.Set();
}
void SetExpectedThreadForIntCallback(Thread* thread) {
expected_thread_ = thread;
}
protected:
enum { kWaitTimeout = 1000 };
AsyncInvokeTest()
: int_value_(0),
invoke_started_(true, false),
expected_thread_(NULL) {}
int int_value_;
Event invoke_started_;
Thread* expected_thread_;
};
TEST_F(AsyncInvokeTest, FireAndForget) {
AsyncInvoker invoker;
// Create and start the thread.
Thread thread;
thread.Start();
// Try calling functor.
bool called = false;
invoker.AsyncInvoke<void>(&thread, FunctorB(&called));
EXPECT_TRUE_WAIT(called, kWaitTimeout);
}
TEST_F(AsyncInvokeTest, WithCallback) {
AsyncInvoker invoker;
// Create and start the thread.
Thread thread;
thread.Start();
// Try calling functor.
SetExpectedThreadForIntCallback(Thread::Current());
invoker.AsyncInvoke(&thread, FunctorA(),
&AsyncInvokeTest::IntCallback,
static_cast<AsyncInvokeTest*>(this));
EXPECT_EQ_WAIT(42, int_value_, kWaitTimeout);
}
TEST_F(AsyncInvokeTest, CancelInvoker) {
// Create and start the thread.
Thread thread;
thread.Start();
// Try destroying invoker during call.
{
AsyncInvoker invoker;
invoker.AsyncInvoke(&thread, FunctorC(),
&AsyncInvokeTest::IntCallback,
static_cast<AsyncInvokeTest*>(this));
}
// With invoker gone, callback should be cancelled.
Thread::Current()->ProcessMessages(kWaitTimeout);
EXPECT_EQ(0, int_value_);
}
TEST_F(AsyncInvokeTest, CancelCallingThread) {
AsyncInvoker invoker;
{ // Create and start the thread.
Thread thread;
thread.Start();
// Try calling functor.
thread.Invoke<void>(Bind(&AsyncInvokeTest::AsyncInvokeIntCallback,
static_cast<AsyncInvokeTest*>(this),
&invoker, Thread::Current()));
// Wait for the call to begin.
ASSERT_TRUE(invoke_started_.Wait(kWaitTimeout));
}
// Calling thread is gone. Return message shouldn't happen.
Thread::Current()->ProcessMessages(kWaitTimeout);
EXPECT_EQ(0, int_value_);
}
TEST_F(AsyncInvokeTest, KillInvokerBeforeExecute) {
Thread thread;
thread.Start();
{
AsyncInvoker invoker;
// Try calling functor.
thread.Invoke<void>(Bind(&AsyncInvokeTest::AsyncInvokeIntCallback,
static_cast<AsyncInvokeTest*>(this),
&invoker, Thread::Current()));
// Wait for the call to begin.
ASSERT_TRUE(invoke_started_.Wait(kWaitTimeout));
}
// Invoker is destroyed. Function should not execute.
Thread::Current()->ProcessMessages(kWaitTimeout);
EXPECT_EQ(0, int_value_);
}
TEST_F(AsyncInvokeTest, Flush) {
AsyncInvoker invoker;
bool flag1 = false;
bool flag2 = false;
// Queue two async calls to the current thread.
invoker.AsyncInvoke<void>(Thread::Current(),
FunctorB(&flag1));
invoker.AsyncInvoke<void>(Thread::Current(),
FunctorB(&flag2));
// Because we haven't pumped messages, these should not have run yet.
EXPECT_FALSE(flag1);
EXPECT_FALSE(flag2);
// Force them to run now.
invoker.Flush(Thread::Current());
EXPECT_TRUE(flag1);
EXPECT_TRUE(flag2);
}
TEST_F(AsyncInvokeTest, FlushWithIds) {
AsyncInvoker invoker;
bool flag1 = false;
bool flag2 = false;
// Queue two async calls to the current thread, one with a message id.
invoker.AsyncInvoke<void>(Thread::Current(),
FunctorB(&flag1),
5);
invoker.AsyncInvoke<void>(Thread::Current(),
FunctorB(&flag2));
// Because we haven't pumped messages, these should not have run yet.
EXPECT_FALSE(flag1);
EXPECT_FALSE(flag2);
// Execute pending calls with id == 5.
invoker.Flush(Thread::Current(), 5);
EXPECT_TRUE(flag1);
EXPECT_FALSE(flag2);
flag1 = false;
// Execute all pending calls. The id == 5 call should not execute again.
invoker.Flush(Thread::Current());
EXPECT_FALSE(flag1);
EXPECT_TRUE(flag2);
}
#ifdef WIN32
class ComThreadTest : public testing::Test, public MessageHandler {
public:

View File

@ -260,6 +260,8 @@
'base/asyncfile.h',
'base/asynchttprequest.cc',
'base/asynchttprequest.h',
'base/asyncinvoker.cc',
'base/asyncinvoker.h',
'base/asyncpacketsocket.h',
'base/asyncresolverinterface.h',
'base/asyncsocket.cc',
@ -282,6 +284,7 @@
'base/bytebuffer.cc',
'base/bytebuffer.h',
'base/byteorder.h',
'base/callback.h',
'base/checks.cc',
'base/checks.h',
'base/common.cc',
@ -383,6 +386,7 @@
'base/scoped_autorelease_pool.h',
'base/scoped_ptr.h',
'base/scoped_ref_ptr.h',
'base/scopedptrcollection.h',
'base/sec_buffer.h',
'base/sha1.cc',
'base/sha1.h',

View File

@ -154,6 +154,7 @@ talk.Library(env, name = "jingle",
srcs = [
"base/asyncfile.cc",
"base/asynchttprequest.cc",
"base/asyncinvoker.cc",
"base/asyncsocket.cc",
"base/asynctcpsocket.cc",
"base/asyncudpsocket.cc",
@ -540,6 +541,7 @@ talk.Unittest(env, name = "base",
"base/buffer_unittest.cc",
"base/bytebuffer_unittest.cc",
"base/byteorder_unittest.cc",
"base/callback_unittest.cc",
"base/cpumonitor_unittest.cc",
"base/crc32_unittest.cc",
"base/event_unittest.cc",
@ -569,6 +571,7 @@ talk.Unittest(env, name = "base",
"base/ratetracker_unittest.cc",
"base/referencecountedsingletonfactory_unittest.cc",
"base/rollingaccumulator_unittest.cc",
"base/scopedptrcollection_unittest.cc",
"base/sha1digest_unittest.cc",
"base/sharedexclusivelock_unittest.cc",
"base/signalthread_unittest.cc",

View File

@ -120,6 +120,7 @@
'base/buffer_unittest.cc',
'base/bytebuffer_unittest.cc',
'base/byteorder_unittest.cc',
'base/callback_unittest.cc',
'base/cpumonitor_unittest.cc',
'base/crc32_unittest.cc',
'base/event_unittest.cc',
@ -148,6 +149,7 @@
'base/ratetracker_unittest.cc',
'base/referencecountedsingletonfactory_unittest.cc',
'base/rollingaccumulator_unittest.cc',
'base/scopedptrcollection_unittest.cc',
'base/sha1digest_unittest.cc',
'base/sharedexclusivelock_unittest.cc',
'base/signalthread_unittest.cc',

View File

@ -168,6 +168,7 @@ struct AudioOptions {
adjust_agc_delta.SetFrom(change.adjust_agc_delta);
experimental_agc.SetFrom(change.experimental_agc);
experimental_aec.SetFrom(change.experimental_aec);
experimental_ns.SetFrom(change.experimental_ns);
aec_dump.SetFrom(change.aec_dump);
experimental_acm.SetFrom(change.experimental_acm);
tx_agc_target_dbov.SetFrom(change.tx_agc_target_dbov);
@ -195,6 +196,7 @@ struct AudioOptions {
conference_mode == o.conference_mode &&
experimental_agc == o.experimental_agc &&
experimental_aec == o.experimental_aec &&
experimental_ns == o.experimental_ns &&
adjust_agc_delta == o.adjust_agc_delta &&
aec_dump == o.aec_dump &&
experimental_acm == o.experimental_acm &&
@ -224,6 +226,7 @@ struct AudioOptions {
ost << ToStringIfSet("agc_delta", adjust_agc_delta);
ost << ToStringIfSet("experimental_agc", experimental_agc);
ost << ToStringIfSet("experimental_aec", experimental_aec);
ost << ToStringIfSet("experimental_ns", experimental_ns);
ost << ToStringIfSet("aec_dump", aec_dump);
ost << ToStringIfSet("experimental_acm", experimental_acm);
ost << ToStringIfSet("tx_agc_target_dbov", tx_agc_target_dbov);
@ -261,6 +264,7 @@ struct AudioOptions {
Settable<int> adjust_agc_delta;
Settable<bool> experimental_agc;
Settable<bool> experimental_aec;
Settable<bool> experimental_ns;
Settable<bool> aec_dump;
Settable<bool> experimental_acm;
// Note that tx_agc_* only applies to non-experimental AGC.
@ -763,8 +767,10 @@ struct VideoSenderInfo : public MediaSenderInfo {
: packets_cached(0),
firs_rcvd(0),
nacks_rcvd(0),
frame_width(0),
frame_height(0),
input_frame_width(0),
input_frame_height(0),
send_frame_width(0),
send_frame_height(0),
framerate_input(0),
framerate_sent(0),
nominal_bitrate(0),
@ -780,8 +786,10 @@ struct VideoSenderInfo : public MediaSenderInfo {
int packets_cached;
int firs_rcvd;
int nacks_rcvd;
int frame_width;
int frame_height;
int input_frame_width;
int input_frame_height;
int send_frame_width;
int send_frame_height;
int framerate_input;
int framerate_sent;
int nominal_bitrate;

View File

@ -162,8 +162,9 @@ float VideoAdapter::FindLowerScale(int width, int height,
VideoAdapter::VideoAdapter()
: output_num_pixels_(INT_MAX),
scale_third_(false),
frames_(0),
adapted_frames_(0),
frames_in_(0),
frames_out_(0),
frames_scaled_(0),
adaption_changes_(0),
previous_width_(0),
previous_height_(0),
@ -177,9 +178,13 @@ VideoAdapter::~VideoAdapter() {
void VideoAdapter::SetInputFormat(const VideoFormat& format) {
talk_base::CritScope cs(&critical_section_);
int64 old_input_interval = input_format_.interval;
input_format_ = format;
output_format_.interval = talk_base::_max(
output_format_.interval, input_format_.interval);
if (old_input_interval != input_format_.interval) {
LOG(LS_INFO) << "VAdapt Input Interval: " << input_format_.interval;
}
}
void CoordinatedVideoAdapter::SetInputFormat(const VideoFormat& format) {
@ -207,10 +212,14 @@ void CoordinatedVideoAdapter::SetInputFormat(const VideoFormat& format) {
void VideoAdapter::SetOutputFormat(const VideoFormat& format) {
talk_base::CritScope cs(&critical_section_);
int64 old_output_interval = output_format_.interval;
output_format_ = format;
output_num_pixels_ = output_format_.width * output_format_.height;
output_format_.interval = talk_base::_max(
output_format_.interval, input_format_.interval);
if (old_output_interval != output_format_.interval) {
LOG(LS_INFO) << "VAdapt Output Interval: " << output_format_.interval;
}
}
const VideoFormat& VideoAdapter::input_format() {
@ -245,7 +254,7 @@ bool VideoAdapter::AdaptFrame(const VideoFrame* in_frame,
if (!in_frame || !out_frame) {
return false;
}
++frames_;
++frames_in_;
// Update input to actual frame dimensions.
VideoFormat format(static_cast<int>(in_frame->GetWidth()),
@ -273,6 +282,23 @@ bool VideoAdapter::AdaptFrame(const VideoFrame* in_frame,
}
}
if (should_drop) {
// Show VAdapt log every 90 frames dropped. (3 seconds)
// TODO(fbarchard): Consider GetLogSeverity() to change interval to less
// for LS_VERBOSE and more for LS_INFO.
bool show = (frames_in_ - frames_out_) % 90 == 0;
if (show) {
// TODO(fbarchard): Reduce to LS_VERBOSE when adapter info is not needed
// in default calls.
LOG(LS_INFO) << "VAdapt Drop Frame: " << frames_scaled_
<< " / " << frames_out_
<< " / " << frames_in_
<< " Changes: " << adaption_changes_
<< " Input: " << in_frame->GetWidth()
<< "x" << in_frame->GetHeight()
<< " i" << input_format_.interval
<< " Output: i" << output_format_.interval;
}
*out_frame = NULL;
return true;
}
@ -289,19 +315,22 @@ bool VideoAdapter::AdaptFrame(const VideoFrame* in_frame,
}
if (!StretchToOutputFrame(in_frame)) {
LOG(LS_VERBOSE) << "VAdapt Stretch Failed.";
return false;
}
*out_frame = output_frame_.get();
// Show VAdapt log every 300 frames. (10 seconds)
// TODO(fbarchard): Consider GetLogSeverity() to change interval to less
// for LS_VERBOSE and more for LS_INFO.
bool show = frames_ % 300 == 0;
++frames_out_;
if (in_frame->GetWidth() != (*out_frame)->GetWidth() ||
in_frame->GetHeight() != (*out_frame)->GetHeight()) {
++adapted_frames_;
++frames_scaled_;
}
// Show VAdapt log every 90 frames output. (3 seconds)
// TODO(fbarchard): Consider GetLogSeverity() to change interval to less
// for LS_VERBOSE and more for LS_INFO.
bool show = (frames_out_) % 90 == 0;
// TODO(fbarchard): LOG the previous output resolution and track input
// resolution changes as well. Consider dropping the statistics into their
// own class which could be queried publically.
@ -315,14 +344,17 @@ bool VideoAdapter::AdaptFrame(const VideoFrame* in_frame,
if (show) {
// TODO(fbarchard): Reduce to LS_VERBOSE when adapter info is not needed
// in default calls.
LOG(LS_INFO) << "VAdapt Frame: " << adapted_frames_
<< " / " << frames_
LOG(LS_INFO) << "VAdapt Frame: " << frames_scaled_
<< " / " << frames_out_
<< " / " << frames_in_
<< " Changes: " << adaption_changes_
<< " Input: " << in_frame->GetWidth()
<< "x" << in_frame->GetHeight()
<< " i" << input_format_.interval
<< " Scale: " << scale
<< " Output: " << (*out_frame)->GetWidth()
<< "x" << (*out_frame)->GetHeight()
<< " i" << output_format_.interval
<< " Changed: " << (changed ? "true" : "false");
}
previous_width_ = (*out_frame)->GetWidth();

View File

@ -87,8 +87,9 @@ class VideoAdapter {
VideoFormat output_format_;
int output_num_pixels_;
bool scale_third_; // True if adapter allows scaling to 1/3 and 2/3.
int frames_; // Number of input frames.
int adapted_frames_; // Number of frames scaled.
int frames_in_; // Number of input frames.
int frames_out_; // Number of output frames.
int frames_scaled_; // Number of frames scaled.
int adaption_changes_; // Number of changes in scale factor.
size_t previous_width_; // Previous adapter output width.
size_t previous_height_; // Previous adapter output height.

View File

@ -790,8 +790,8 @@ class VideoMediaChannelTest : public testing::Test,
EXPECT_EQ(0.0, info.senders[0].fraction_lost);
EXPECT_EQ(0, info.senders[0].firs_rcvd);
EXPECT_EQ(0, info.senders[0].nacks_rcvd);
EXPECT_EQ(DefaultCodec().width, info.senders[0].frame_width);
EXPECT_EQ(DefaultCodec().height, info.senders[0].frame_height);
EXPECT_EQ(DefaultCodec().width, info.senders[0].send_frame_width);
EXPECT_EQ(DefaultCodec().height, info.senders[0].send_frame_height);
EXPECT_GT(info.senders[0].framerate_input, 0);
EXPECT_GT(info.senders[0].framerate_sent, 0);
@ -848,8 +848,8 @@ class VideoMediaChannelTest : public testing::Test,
EXPECT_EQ(0.0, info.senders[0].fraction_lost);
EXPECT_EQ(0, info.senders[0].firs_rcvd);
EXPECT_EQ(0, info.senders[0].nacks_rcvd);
EXPECT_EQ(DefaultCodec().width, info.senders[0].frame_width);
EXPECT_EQ(DefaultCodec().height, info.senders[0].frame_height);
EXPECT_EQ(DefaultCodec().width, info.senders[0].send_frame_width);
EXPECT_EQ(DefaultCodec().height, info.senders[0].send_frame_height);
EXPECT_GT(info.senders[0].framerate_input, 0);
EXPECT_GT(info.senders[0].framerate_sent, 0);
@ -918,12 +918,12 @@ class VideoMediaChannelTest : public testing::Test,
info.senders[0].packets_sent + info.senders[1].packets_sent);
EXPECT_EQ(1U, info.senders[0].ssrcs().size());
EXPECT_EQ(1234U, info.senders[0].ssrcs()[0]);
EXPECT_EQ(DefaultCodec().width, info.senders[0].frame_width);
EXPECT_EQ(DefaultCodec().height, info.senders[0].frame_height);
EXPECT_EQ(DefaultCodec().width, info.senders[0].send_frame_width);
EXPECT_EQ(DefaultCodec().height, info.senders[0].send_frame_height);
EXPECT_EQ(1U, info.senders[1].ssrcs().size());
EXPECT_EQ(5678U, info.senders[1].ssrcs()[0]);
EXPECT_EQ(kTestWidth, info.senders[1].frame_width);
EXPECT_EQ(kTestHeight, info.senders[1].frame_height);
EXPECT_EQ(kTestWidth, info.senders[1].send_frame_width);
EXPECT_EQ(kTestHeight, info.senders[1].send_frame_height);
// The capturer must be unregistered here as it runs out of it's scope next.
EXPECT_TRUE(channel_->SetCapturer(5678, NULL));
}

View File

@ -50,10 +50,10 @@ bool V4LLookup::CheckIsV4L2Device(const std::string& device_path) {
is_v4l2 = true;
} else {
LOG(LS_ERROR) << "VIDIOC_QUERYCAP failed for " << device_path;
LOG_ERRNO(LS_ERROR) << "VIDIOC_QUERYCAP failed for " << device_path;
}
} else {
LOG(LS_ERROR) << "Failed to open " << device_path;
LOG_ERRNO(LS_ERROR) << "Failed to open " << device_path;
}
}
}

View File

@ -83,13 +83,18 @@ class FakeWebRtcVideoCaptureModule : public webrtc::VideoCaptureModule {
virtual int32_t RegisterCaptureDataCallback(
webrtc::VideoCaptureDataCallback& callback) {
callback_ = &callback;
return 0;
}
virtual void DeRegisterCaptureDataCallback() { callback_ = NULL; }
virtual void RegisterCaptureCallback(webrtc::VideoCaptureFeedBack& callback) {
// Not implemented.
virtual int32_t DeRegisterCaptureDataCallback() {
callback_ = NULL;
return 0;
}
virtual void DeRegisterCaptureCallback() {
// Not implemented.
virtual int32_t RegisterCaptureCallback(
webrtc::VideoCaptureFeedBack& callback) {
return -1; // not implemented
}
virtual int32_t DeRegisterCaptureCallback() {
return 0;
}
virtual int32_t SetCaptureDelay(int32_t delay) {
delay_ = delay;

View File

@ -2300,8 +2300,18 @@ bool WebRtcVideoMediaChannel::GetStats(VideoMediaInfo* info) {
sinfo.firs_rcvd = -1;
sinfo.nacks_rcvd = -1;
sinfo.rtt_ms = -1;
sinfo.frame_width = static_cast<int>(channel_stream_info->width());
sinfo.frame_height = static_cast<int>(channel_stream_info->height());
sinfo.input_frame_width = static_cast<int>(channel_stream_info->width());
sinfo.input_frame_height =
static_cast<int>(channel_stream_info->height());
webrtc::VideoCodec vie_codec;
if (engine()->vie()->codec()->GetSendCodec(channel_id, vie_codec) == 0) {
sinfo.send_frame_width = vie_codec.width;
sinfo.send_frame_height = vie_codec.height;
} else {
sinfo.send_frame_width = -1;
sinfo.send_frame_height = -1;
LOG_RTCERR1(GetSendCodec, channel_id);
}
sinfo.framerate_input = channel_stream_info->framerate();
sinfo.framerate_sent = send_channel->encoder_observer()->framerate();
sinfo.nominal_bitrate = send_channel->encoder_observer()->bitrate();

View File

@ -229,6 +229,7 @@ static AudioOptions GetDefaultEngineOptions() {
options.adjust_agc_delta.Set(0);
options.experimental_agc.Set(false);
options.experimental_aec.Set(false);
options.experimental_ns.Set(false);
options.aec_dump.Set(false);
options.experimental_acm.Set(false);
return options;
@ -717,6 +718,7 @@ bool WebRtcVoiceEngine::ApplyOptions(const AudioOptions& options_in) {
options.typing_detection.Set(false);
options.experimental_agc.Set(false);
options.experimental_aec.Set(false);
options.experimental_ns.Set(false);
#endif
LOG(LS_INFO) << "Applying audio options: " << options.ToString();
@ -804,6 +806,25 @@ bool WebRtcVoiceEngine::ApplyOptions(const AudioOptions& options_in) {
}
}
#ifdef USE_WEBRTC_DEV_BRANCH
bool experimental_ns;
if (options.experimental_ns.Get(&experimental_ns)) {
webrtc::AudioProcessing* audioproc =
voe_wrapper_->base()->audio_processing();
// We check audioproc for the benefit of tests, since FakeWebRtcVoiceEngine
// returns NULL on audio_processing().
if (audioproc) {
if (audioproc->EnableExperimentalNs(experimental_ns) == -1) {
LOG_RTCERR1(EnableExperimentalNs, experimental_ns);
return false;
}
} else {
LOG(LS_VERBOSE) << "Experimental noise suppression set to "
<< experimental_ns;
}
}
#endif // USE_WEBRTC_DEV_BRANCH
bool highpass_filter;
if (options.highpass_filter.Get(&highpass_filter)) {
if (voep->EnableHighPassFilter(highpass_filter) == -1) {

View File

@ -328,7 +328,7 @@ void UDPPort::OnStunBindingRequestSucceeded(
// related address is local socket address.
set_related_address(socket_->GetLocalAddress());
AddAddress(stun_addr, socket_->GetLocalAddress(), UDP_PROTOCOL_NAME,
STUN_PORT_TYPE, ICE_TYPE_PREFERENCE_PRFLX, false);
STUN_PORT_TYPE, ICE_TYPE_PREFERENCE_SRFLX, false);
}
SetResult(true);
}

File diff suppressed because it is too large Load Diff

View File

@ -248,12 +248,6 @@ class BaseChannel
SrtpFilter* srtp_filter() { return &srtp_filter_; }
bool rtcp() const { return rtcp_; }
void Send(uint32 id, talk_base::MessageData* pdata = NULL);
void Post(uint32 id, talk_base::MessageData* pdata = NULL);
void PostDelayed(int cmsDelay, uint32 id = 0,
talk_base::MessageData* pdata = NULL);
void Clear(uint32 id = talk_base::MQID_ANY,
talk_base::MessageList* removed = NULL);
void FlushRtcpMessages();
// NetworkInterface implementation, called by MediaEngine
@ -346,6 +340,12 @@ class BaseChannel
virtual void OnConnectionMonitorUpdate(SocketMonitor* monitor,
const std::vector<ConnectionInfo>& infos) = 0;
// Helper function for invoking bool-returning methods on the worker thread.
template <class FunctorT>
bool InvokeOnWorker(const FunctorT& functor) {
return worker_thread_->Invoke<bool>(functor);
}
private:
sigslot::signal3<const void*, size_t, bool> SignalSendPacketPreCrypto;
sigslot::signal3<const void*, size_t, bool> SignalSendPacketPostCrypto;
@ -470,7 +470,6 @@ class VoiceChannel : public BaseChannel {
bool SetRingbackTone_w(const void* buf, int len);
bool PlayRingbackTone_w(uint32 ssrc, bool play, bool loop);
void HandleEarlyMediaTimeout();
bool CanInsertDtmf_w();
bool InsertDtmf_w(uint32 ssrc, int event, int duration, int flags);
bool SetOutputScaling_w(uint32 ssrc, double left, double right);
bool GetStats_w(VoiceMediaInfo* stats);
@ -485,9 +484,6 @@ class VoiceChannel : public BaseChannel {
void OnVoiceChannelError(uint32 ssrc, VoiceMediaChannel::Error error);
void SendLastMediaError();
void OnSrtpError(uint32 ssrc, SrtpFilter::Mode mode, SrtpFilter::Error error);
// Configuration and setting.
bool SetChannelOptions_w(const AudioOptions& options);
bool SetRenderer_w(uint32 ssrc, AudioRenderer* renderer, bool is_local);
static const int kEarlyMediaTimeout = 1000;
bool received_media_;
@ -557,7 +553,7 @@ class VideoChannel : public BaseChannel {
private:
typedef std::map<uint32, VideoCapturer*> ScreencastMap;
struct ScreencastDetailsMessageData;
struct ScreencastDetailsData;
// overrides from BaseChannel
virtual void ChangeState();
@ -568,22 +564,13 @@ class VideoChannel : public BaseChannel {
virtual bool SetRemoteContent_w(const MediaContentDescription* content,
ContentAction action,
std::string* error_desc);
void SendIntraFrame_w() {
media_channel()->SendIntraFrame();
}
void RequestIntraFrame_w() {
media_channel()->RequestIntraFrame();
}
bool ApplyViewRequest_w(const ViewRequest& request);
void SetRenderer_w(uint32 ssrc, VideoRenderer* renderer);
VideoCapturer* AddScreencast_w(uint32 ssrc, const ScreencastId& id);
bool SetCapturer_w(uint32 ssrc, VideoCapturer* capturer);
bool RemoveScreencast_w(uint32 ssrc);
void OnScreencastWindowEvent_s(uint32 ssrc, talk_base::WindowEvent we);
bool IsScreencasting_w() const;
void ScreencastDetails_w(ScreencastDetailsMessageData* d) const;
void GetScreencastDetails_w(ScreencastDetailsData* d) const;
void SetScreenCaptureFactory_w(
ScreenCapturerFactory* screencapture_factory);
bool GetStats_w(VideoMediaInfo* stats);
@ -601,8 +588,6 @@ class VideoChannel : public BaseChannel {
void OnVideoChannelError(uint32 ssrc, VideoMediaChannel::Error error);
void OnSrtpError(uint32 ssrc, SrtpFilter::Mode mode, SrtpFilter::Error error);
// Configuration and setting.
bool SetChannelOptions_w(const VideoOptions& options);
VoiceChannel* voice_channel_;
VideoRenderer* renderer_;