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:
parent
9510e53cc0
commit
9cf037b831
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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[] =
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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));
|
||||
|
@ -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,
|
||||
|
@ -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[];
|
||||
|
101
talk/base/asyncinvoker-inl.h
Normal file
101
talk/base/asyncinvoker-inl.h
Normal 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
78
talk/base/asyncinvoker.cc
Normal 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
167
talk/base/asyncinvoker.h
Normal 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_
|
207
talk/base/bind.h
207
talk/base/bind.h
@ -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
|
||||
|
@ -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
|
||||
|
||||
]]
|
||||
|
@ -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
291
talk/base/callback.h
Normal 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
123
talk/base/callback.h.pump
Normal 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_
|
98
talk/base/callback_unittest.cc
Normal file
98
talk/base/callback_unittest.cc
Normal 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
|
@ -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_
|
||||
|
77
talk/base/scopedptrcollection.h
Normal file
77
talk/base/scopedptrcollection.h
Normal 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_
|
90
talk/base/scopedptrcollection_unittest.cc
Normal file
90
talk/base/scopedptrcollection_unittest.cc
Normal 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
|
@ -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
|
||||
|
@ -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:
|
||||
|
@ -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',
|
||||
|
@ -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",
|
||||
|
@ -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',
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -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.
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -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) {
|
||||
|
@ -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
@ -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_;
|
||||
|
Loading…
x
Reference in New Issue
Block a user