aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsergeyu@chromium.org <sergeyu@chromium.org@4adac7df-926f-26a2-2b94-8c16560cd09d>2014-02-07 19:03:26 +0000
committersergeyu@chromium.org <sergeyu@chromium.org@4adac7df-926f-26a2-2b94-8c16560cd09d>2014-02-07 19:03:26 +0000
commit9cf037b83184374230c6825e4aa407cdafaba434 (patch)
tree72f611bb7f3f048c96b6378225abcaa1694cf8a1
parent9510e53cc06b0aa5be2be78fbab375216067eea2 (diff)
downloadwebrtc-9cf037b83184374230c6825e4aa407cdafaba434.tar.gz
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
-rw-r--r--talk/app/webrtc/javatests/src/org/webrtc/PeerConnectionTest.java2
-rw-r--r--talk/app/webrtc/localaudiosource.cc3
-rw-r--r--talk/app/webrtc/mediaconstraintsinterface.cc2
-rw-r--r--talk/app/webrtc/mediaconstraintsinterface.h1
-rw-r--r--talk/app/webrtc/mediastreamhandler.cc2
-rw-r--r--talk/app/webrtc/peerconnection_unittest.cc5
-rw-r--r--talk/app/webrtc/statscollector.cc16
-rw-r--r--talk/app/webrtc/statstypes.h3
-rw-r--r--talk/base/asyncinvoker-inl.h101
-rw-r--r--talk/base/asyncinvoker.cc78
-rw-r--r--talk/base/asyncinvoker.h167
-rw-r--r--talk/base/bind.h207
-rw-r--r--talk/base/bind.h.pump30
-rw-r--r--talk/base/bind_unittest.cc10
-rw-r--r--talk/base/callback.h291
-rw-r--r--talk/base/callback.h.pump123
-rw-r--r--talk/base/callback_unittest.cc98
-rw-r--r--talk/base/messagehandler.h39
-rw-r--r--talk/base/scopedptrcollection.h77
-rw-r--r--talk/base/scopedptrcollection_unittest.cc90
-rw-r--r--talk/base/thread.h27
-rw-r--r--talk/base/thread_unittest.cc163
-rwxr-xr-xtalk/libjingle.gyp4
-rw-r--r--talk/libjingle.scons3
-rwxr-xr-xtalk/libjingle_tests.gyp2
-rw-r--r--talk/media/base/mediachannel.h16
-rw-r--r--talk/media/base/videoadapter.cc52
-rw-r--r--talk/media/base/videoadapter.h5
-rw-r--r--talk/media/base/videoengine_unittest.h16
-rw-r--r--talk/media/devices/v4llookup.cc4
-rw-r--r--talk/media/webrtc/fakewebrtcvideocapturemodule.h15
-rw-r--r--talk/media/webrtc/webrtcvideoengine.cc14
-rw-r--r--talk/media/webrtc/webrtcvoiceengine.cc21
-rw-r--r--talk/p2p/base/stunport.cc2
-rw-r--r--talk/session/media/channel.cc682
-rw-r--r--talk/session/media/channel.h31
36 files changed, 1715 insertions, 687 deletions
diff --git a/talk/app/webrtc/javatests/src/org/webrtc/PeerConnectionTest.java b/talk/app/webrtc/javatests/src/org/webrtc/PeerConnectionTest.java
index 2a06ff4177..3bf128e16f 100644
--- a/talk/app/webrtc/javatests/src/org/webrtc/PeerConnectionTest.java
+++ b/talk/app/webrtc/javatests/src/org/webrtc/PeerConnectionTest.java
@@ -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);
diff --git a/talk/app/webrtc/localaudiosource.cc b/talk/app/webrtc/localaudiosource.cc
index 7ac59fc4cc..ab9ae4fa99 100644
--- a/talk/app/webrtc/localaudiosource.cc
+++ b/talk/app/webrtc/localaudiosource.cc
@@ -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)
diff --git a/talk/app/webrtc/mediaconstraintsinterface.cc b/talk/app/webrtc/mediaconstraintsinterface.cc
index 2512932011..63d2be009b 100644
--- a/talk/app/webrtc/mediaconstraintsinterface.cc
+++ b/talk/app/webrtc/mediaconstraintsinterface.cc
@@ -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[] =
diff --git a/talk/app/webrtc/mediaconstraintsinterface.h b/talk/app/webrtc/mediaconstraintsinterface.h
index 7a207e4004..fae065cbc7 100644
--- a/talk/app/webrtc/mediaconstraintsinterface.h
+++ b/talk/app/webrtc/mediaconstraintsinterface.h
@@ -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
diff --git a/talk/app/webrtc/mediastreamhandler.cc b/talk/app/webrtc/mediastreamhandler.cc
index 932d55ee7b..a94eef322a 100644
--- a/talk/app/webrtc/mediastreamhandler.cc
+++ b/talk/app/webrtc/mediastreamhandler.cc
@@ -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);
}
diff --git a/talk/app/webrtc/peerconnection_unittest.cc b/talk/app/webrtc/peerconnection_unittest.cc
index edf79f5a75..1b6d73d030 100644
--- a/talk/app/webrtc/peerconnection_unittest.cc
+++ b/talk/app/webrtc/peerconnection_unittest.cc
@@ -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));
diff --git a/talk/app/webrtc/statscollector.cc b/talk/app/webrtc/statscollector.cc
index 7e1e7eec66..2efc11b1cb 100644
--- a/talk/app/webrtc/statscollector.cc
+++ b/talk/app/webrtc/statscollector.cc
@@ -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,
diff --git a/talk/app/webrtc/statstypes.h b/talk/app/webrtc/statstypes.h
index 6890f9e017..9110da3fb9 100644
--- a/talk/app/webrtc/statstypes.h
+++ b/talk/app/webrtc/statstypes.h
@@ -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[];
diff --git a/talk/base/asyncinvoker-inl.h b/talk/base/asyncinvoker-inl.h
new file mode 100644
index 0000000000..c4afd3a194
--- /dev/null
+++ b/talk/base/asyncinvoker-inl.h
@@ -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_
diff --git a/talk/base/asyncinvoker.cc b/talk/base/asyncinvoker.cc
new file mode 100644
index 0000000000..63171be401
--- /dev/null
+++ b/talk/base/asyncinvoker.cc
@@ -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
diff --git a/talk/base/asyncinvoker.h b/talk/base/asyncinvoker.h
new file mode 100644
index 0000000000..fabdbdcbd2
--- /dev/null
+++ b/talk/base/asyncinvoker.h
@@ -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_
diff --git a/talk/base/bind.h b/talk/base/bind.h
index 622cc679db..5b4eaac943 100644
--- a/talk/base/bind.h
+++ b/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>
@@ -104,6 +116,16 @@ Bind(FP_T(method), const ObjectT* 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,
class P1>
@@ -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,
@@ -145,6 +182,18 @@ Bind(FP_T(method), const ObjectT* object,
}
#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,
class P1,
@@ -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,
@@ -194,6 +261,20 @@ Bind(FP_T(method), const ObjectT* object,
}
#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,
class P1,
@@ -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,
@@ -251,6 +353,22 @@ Bind(FP_T(method), const ObjectT* object,
}
#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,
class P1,
@@ -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,
@@ -316,6 +458,24 @@ Bind(FP_T(method), const ObjectT* object,
}
#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,
class P1,
@@ -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,
@@ -389,6 +576,26 @@ Bind(FP_T(method), const ObjectT* object,
}
#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
diff --git a/talk/base/bind.h.pump b/talk/base/bind.h.pump
index 7f4c39e634..2ebb895515 100644
--- a/talk/base/bind.h.pump
+++ b/talk/base/bind.h.pump
@@ -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 [[,
@@ -115,6 +133,18 @@ Bind(FP_T(method), const ObjectT* object$for 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
]]
diff --git a/talk/base/bind_unittest.cc b/talk/base/bind_unittest.cc
index 81bbddd6b7..78ac278376 100644
--- a/talk/base/bind_unittest.cc
+++ b/talk/base/bind_unittest.cc
@@ -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
diff --git a/talk/base/callback.h b/talk/base/callback.h
new file mode 100644
index 0000000000..e77276875b
--- /dev/null
+++ b/talk/base/callback.h
@@ -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_
diff --git a/talk/base/callback.h.pump b/talk/base/callback.h.pump
new file mode 100644
index 0000000000..ae9ab87de0
--- /dev/null
+++ b/talk/base/callback.h.pump
@@ -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_ \ No newline at end of file
diff --git a/talk/base/callback_unittest.cc b/talk/base/callback_unittest.cc
new file mode 100644
index 0000000000..c7ca00f0fd
--- /dev/null
+++ b/talk/base/callback_unittest.cc
@@ -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
diff --git a/talk/base/messagehandler.h b/talk/base/messagehandler.h
index 913edf8ce2..8b9e5f6d13 100644
--- a/talk/base/messagehandler.h
+++ b/talk/base/messagehandler.h
@@ -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_
diff --git a/talk/base/scopedptrcollection.h b/talk/base/scopedptrcollection.h
new file mode 100644
index 0000000000..ec2726e272
--- /dev/null
+++ b/talk/base/scopedptrcollection.h
@@ -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_
diff --git a/talk/base/scopedptrcollection_unittest.cc b/talk/base/scopedptrcollection_unittest.cc
new file mode 100644
index 0000000000..dd9002e42f
--- /dev/null
+++ b/talk/base/scopedptrcollection_unittest.cc
@@ -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
diff --git a/talk/base/thread.h b/talk/base/thread.h
index 4dc09f641d..316f041974 100644
--- a/talk/base/thread.h
+++ b/talk/base/thread.h
@@ -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
diff --git a/talk/base/thread_unittest.cc b/talk/base/thread_unittest.cc
index 896fbabc5f..ddf6326a24 100644
--- a/talk/base/thread_unittest.cc
+++ b/talk/base/thread_unittest.cc
@@ -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:
diff --git a/talk/libjingle.gyp b/talk/libjingle.gyp
index bde7ee0a6f..3904a0feb5 100755
--- a/talk/libjingle.gyp
+++ b/talk/libjingle.gyp
@@ -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',
diff --git a/talk/libjingle.scons b/talk/libjingle.scons
index d879cc277a..dc5e9a0671 100644
--- a/talk/libjingle.scons
+++ b/talk/libjingle.scons
@@ -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",
diff --git a/talk/libjingle_tests.gyp b/talk/libjingle_tests.gyp
index e36a369ef6..038fb4f1ae 100755
--- a/talk/libjingle_tests.gyp
+++ b/talk/libjingle_tests.gyp
@@ -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',
diff --git a/talk/media/base/mediachannel.h b/talk/media/base/mediachannel.h
index c2ea26f1bd..ef87c9e92d 100644
--- a/talk/media/base/mediachannel.h
+++ b/talk/media/base/mediachannel.h
@@ -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;
diff --git a/talk/media/base/videoadapter.cc b/talk/media/base/videoadapter.cc
index 3cd6cac96c..29be805317 100644
--- a/talk/media/base/videoadapter.cc
+++ b/talk/media/base/videoadapter.cc
@@ -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();
diff --git a/talk/media/base/videoadapter.h b/talk/media/base/videoadapter.h
index 272df72de6..6b1cdc5f93 100644
--- a/talk/media/base/videoadapter.h
+++ b/talk/media/base/videoadapter.h
@@ -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.
diff --git a/talk/media/base/videoengine_unittest.h b/talk/media/base/videoengine_unittest.h
index b667cb0f0a..e1c4a7d5c0 100644
--- a/talk/media/base/videoengine_unittest.h
+++ b/talk/media/base/videoengine_unittest.h
@@ -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));
}
diff --git a/talk/media/devices/v4llookup.cc b/talk/media/devices/v4llookup.cc
index ff128a4ae3..e1ef9feaa0 100644
--- a/talk/media/devices/v4llookup.cc
+++ b/talk/media/devices/v4llookup.cc
@@ -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;
}
}
}
diff --git a/talk/media/webrtc/fakewebrtcvideocapturemodule.h b/talk/media/webrtc/fakewebrtcvideocapturemodule.h
index 5628e01bbe..d63e710a7b 100644
--- a/talk/media/webrtc/fakewebrtcvideocapturemodule.h
+++ b/talk/media/webrtc/fakewebrtcvideocapturemodule.h
@@ -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;
diff --git a/talk/media/webrtc/webrtcvideoengine.cc b/talk/media/webrtc/webrtcvideoengine.cc
index 178d538c2f..d2e73eae51 100644
--- a/talk/media/webrtc/webrtcvideoengine.cc
+++ b/talk/media/webrtc/webrtcvideoengine.cc
@@ -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();
diff --git a/talk/media/webrtc/webrtcvoiceengine.cc b/talk/media/webrtc/webrtcvoiceengine.cc
index 4ad2ff502c..f1030bd621 100644
--- a/talk/media/webrtc/webrtcvoiceengine.cc
+++ b/talk/media/webrtc/webrtcvoiceengine.cc
@@ -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) {
diff --git a/talk/p2p/base/stunport.cc b/talk/p2p/base/stunport.cc
index def3c9b4da..cee2fc4eee 100644
--- a/talk/p2p/base/stunport.cc
+++ b/talk/p2p/base/stunport.cc
@@ -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);
}
diff --git a/talk/session/media/channel.cc b/talk/session/media/channel.cc
index 9a76d51f8b..bc6bd0981d 100644
--- a/talk/session/media/channel.cc
+++ b/talk/session/media/channel.cc
@@ -27,6 +27,7 @@
#include "talk/session/media/channel.h"
+#include "talk/base/bind.h"
#include "talk/base/buffer.h"
#include "talk/base/byteorder.h"
#include "talk/base/common.h"
@@ -42,44 +43,17 @@
namespace cricket {
+using talk_base::Bind;
+
enum {
- MSG_ENABLE = 1,
- MSG_DISABLE,
- MSG_MUTESTREAM,
- MSG_ISSTREAMMUTED,
- MSG_SETREMOTECONTENT,
- MSG_SETLOCALCONTENT,
- MSG_EARLYMEDIATIMEOUT,
- MSG_CANINSERTDTMF,
- MSG_INSERTDTMF,
- MSG_GETSTATS,
- MSG_SETRENDERER,
- MSG_ADDRECVSTREAM,
- MSG_REMOVERECVSTREAM,
- MSG_ADDSENDSTREAM,
- MSG_REMOVESENDSTREAM,
- MSG_SETRINGBACKTONE,
- MSG_PLAYRINGBACKTONE,
- MSG_ADDSCREENCAST,
- MSG_REMOVESCREENCAST,
- MSG_SENDINTRAFRAME,
- MSG_REQUESTINTRAFRAME,
+ MSG_EARLYMEDIATIMEOUT = 1,
MSG_SCREENCASTWINDOWEVENT,
MSG_RTPPACKET,
MSG_RTCPPACKET,
MSG_CHANNEL_ERROR,
- MSG_SETCHANNELOPTIONS,
- MSG_SCALEVOLUME,
- MSG_HANDLEVIEWREQUEST,
MSG_READYTOSENDDATA,
- MSG_SENDDATA,
MSG_DATARECEIVED,
- MSG_SETCAPTURER,
- MSG_ISSCREENCASTING,
- MSG_GETSCREENCASTDETAILS,
- MSG_SETSCREENCASTFACTORY,
MSG_FIRSTPACKETRECEIVED,
- MSG_SESSION_ERROR,
};
// Value specified in RFC 5764.
@@ -112,133 +86,11 @@ VideoChannel::ScreenCapturerFactory* CreateScreenCapturerFactory() {
return new NullScreenCapturerFactory();
}
-struct SetContentData : public talk_base::MessageData {
- SetContentData(const MediaContentDescription* content,
- ContentAction action,
- std::string* error_desc)
- : content(content),
- action(action),
- error_desc(error_desc),
- result(false) {
- }
- const MediaContentDescription* content;
- ContentAction action;
- std::string* error_desc;
- bool result;
-};
-
-struct SetBandwidthData : public talk_base::MessageData {
- explicit SetBandwidthData(int value) : value(value), result(false) {}
- int value;
- bool result;
-};
-
-struct SetRingbackToneMessageData : public talk_base::MessageData {
- SetRingbackToneMessageData(const void* b, int l)
- : buf(b),
- len(l),
- result(false) {
- }
- const void* buf;
- int len;
- bool result;
-};
-
-struct PlayRingbackToneMessageData : public talk_base::MessageData {
- PlayRingbackToneMessageData(uint32 s, bool p, bool l)
- : ssrc(s),
- play(p),
- loop(l),
- result(false) {
- }
- uint32 ssrc;
- bool play;
- bool loop;
- bool result;
-};
-typedef talk_base::TypedMessageData<bool> BoolMessageData;
-struct DtmfMessageData : public talk_base::MessageData {
- DtmfMessageData(uint32 ssrc, int event, int duration, int flags)
- : ssrc(ssrc),
- event(event),
- duration(duration),
- flags(flags),
- result(false) {
- }
- uint32 ssrc;
- int event;
- int duration;
- int flags;
- bool result;
-};
-struct ScaleVolumeMessageData : public talk_base::MessageData {
- ScaleVolumeMessageData(uint32 s, double l, double r)
- : ssrc(s),
- left(l),
- right(r),
- result(false) {
- }
- uint32 ssrc;
- double left;
- double right;
- bool result;
-};
-
-struct VoiceStatsMessageData : public talk_base::MessageData {
- explicit VoiceStatsMessageData(VoiceMediaInfo* stats)
- : result(false),
- stats(stats) {
- }
- bool result;
- VoiceMediaInfo* stats;
-};
-
-struct VideoStatsMessageData : public talk_base::MessageData {
- explicit VideoStatsMessageData(VideoMediaInfo* stats)
- : result(false),
- stats(stats) {
- }
- bool result;
- VideoMediaInfo* stats;
-};
-
struct PacketMessageData : public talk_base::MessageData {
talk_base::Buffer packet;
talk_base::DiffServCodePoint dscp;
};
-struct AudioRenderMessageData: public talk_base::MessageData {
- AudioRenderMessageData(uint32 s, AudioRenderer* r, bool l)
- : ssrc(s), renderer(r), is_local(l), result(false) {}
- uint32 ssrc;
- AudioRenderer* renderer;
- bool is_local;
- bool result;
-};
-
-struct VideoRenderMessageData : public talk_base::MessageData {
- VideoRenderMessageData(uint32 s, VideoRenderer* r) : ssrc(s), renderer(r) {}
- uint32 ssrc;
- VideoRenderer* renderer;
-};
-
-struct AddScreencastMessageData : public talk_base::MessageData {
- AddScreencastMessageData(uint32 s, const ScreencastId& id)
- : ssrc(s),
- window_id(id),
- result(NULL) {
- }
- uint32 ssrc;
- ScreencastId window_id;
- VideoCapturer* result;
-};
-
-struct RemoveScreencastMessageData : public talk_base::MessageData {
- explicit RemoveScreencastMessageData(uint32 s) : ssrc(s), result(false) {}
- uint32 ssrc;
- bool result;
-};
-
struct ScreencastEventMessageData : public talk_base::MessageData {
ScreencastEventMessageData(uint32 s, talk_base::WindowEvent we)
: ssrc(s),
@@ -248,15 +100,6 @@ struct ScreencastEventMessageData : public talk_base::MessageData {
talk_base::WindowEvent event;
};
-struct ViewRequestMessageData : public talk_base::MessageData {
- explicit ViewRequestMessageData(const ViewRequest& r)
- : request(r),
- result(false) {
- }
- ViewRequest request;
- bool result;
-};
-
struct VoiceChannelErrorMessageData : public talk_base::MessageData {
VoiceChannelErrorMessageData(uint32 in_ssrc,
VoiceMediaChannel::Error in_error)
@@ -286,78 +129,9 @@ struct DataChannelErrorMessageData : public talk_base::MessageData {
DataMediaChannel::Error error;
};
-struct SessionErrorMessageData : public talk_base::MessageData {
- SessionErrorMessageData(cricket::BaseSession::Error error,
- const std::string& error_desc)
- : error_(error),
- error_desc_(error_desc) {}
- BaseSession::Error error_;
- std::string error_desc_;
-};
-
-struct SsrcMessageData : public talk_base::MessageData {
- explicit SsrcMessageData(uint32 ssrc) : ssrc(ssrc), result(false) {}
- uint32 ssrc;
- bool result;
-};
-
-struct StreamMessageData : public talk_base::MessageData {
- explicit StreamMessageData(const StreamParams& in_sp)
- : sp(in_sp),
- result(false) {
- }
- StreamParams sp;
- bool result;
-};
-
-struct MuteStreamData : public talk_base::MessageData {
- MuteStreamData(uint32 ssrc, bool mute)
- : ssrc(ssrc), mute(mute), result(false) {}
- uint32 ssrc;
- bool mute;
- bool result;
-};
-
-struct AudioOptionsMessageData : public talk_base::MessageData {
- explicit AudioOptionsMessageData(const AudioOptions& options)
- : options(options),
- result(false) {
- }
- AudioOptions options;
- bool result;
-};
-
-struct VideoOptionsMessageData : public talk_base::MessageData {
- explicit VideoOptionsMessageData(const VideoOptions& options)
- : options(options),
- result(false) {
- }
- VideoOptions options;
- bool result;
-};
-
-struct SetCapturerMessageData : public talk_base::MessageData {
- SetCapturerMessageData(uint32 s, VideoCapturer* c)
- : ssrc(s),
- capturer(c),
- result(false) {
- }
- uint32 ssrc;
- VideoCapturer* capturer;
- bool result;
-};
-
-struct IsScreencastingMessageData : public talk_base::MessageData {
- IsScreencastingMessageData()
- : result(false) {
- }
- bool result;
-};
-
-struct VideoChannel::ScreencastDetailsMessageData :
- public talk_base::MessageData {
- explicit ScreencastDetailsMessageData(uint32 s)
+struct VideoChannel::ScreencastDetailsData {
+ explicit ScreencastDetailsData(uint32 s)
: ssrc(s), fps(0), screencast_max_pixels(0) {
}
uint32 ssrc;
@@ -365,14 +139,6 @@ struct VideoChannel::ScreencastDetailsMessageData :
int screencast_max_pixels;
};
-struct SetScreenCaptureFactoryMessageData : public talk_base::MessageData {
- explicit SetScreenCaptureFactoryMessageData(
- VideoChannel::ScreenCapturerFactory* f)
- : screencapture_factory(f) {
- }
- VideoChannel::ScreenCapturerFactory* screencapture_factory;
-};
-
static const char* PacketType(bool rtcp) {
return (!rtcp) ? "RTP" : "RTCP";
}
@@ -430,7 +196,7 @@ BaseChannel::~BaseChannel() {
Deinit();
StopConnectionMonitor();
FlushRtcpMessages(); // Send any outstanding RTCP packets.
- Clear(); // eats any outstanding messages or packets
+ worker_thread_->Clear(this); // eats any outstanding messages or packets
// We must destroy the media channel before the transport channel, otherwise
// the media channel may try to send on the dead transport channel. NULLing
// is not an effective strategy since the sends will come on another thread.
@@ -478,63 +244,51 @@ void BaseChannel::Deinit() {
media_channel_->SetInterface(NULL);
}
-// Can be called from thread other than worker thread
bool BaseChannel::Enable(bool enable) {
- Send(enable ? MSG_ENABLE : MSG_DISABLE);
+ worker_thread_->Invoke<void>(Bind(
+ enable ? &BaseChannel::EnableMedia_w : &BaseChannel::DisableMedia_w,
+ this));
return true;
}
-// Can be called from thread other than worker thread
bool BaseChannel::MuteStream(uint32 ssrc, bool mute) {
- MuteStreamData data(ssrc, mute);
- Send(MSG_MUTESTREAM, &data);
- return data.result;
+ return InvokeOnWorker(Bind(&BaseChannel::MuteStream_w, this, ssrc, mute));
}
bool BaseChannel::IsStreamMuted(uint32 ssrc) {
- SsrcMessageData data(ssrc);
- Send(MSG_ISSTREAMMUTED, &data);
- return data.result;
+ return InvokeOnWorker(Bind(&BaseChannel::IsStreamMuted_w, this, ssrc));
}
bool BaseChannel::AddRecvStream(const StreamParams& sp) {
- StreamMessageData data(sp);
- Send(MSG_ADDRECVSTREAM, &data);
- return data.result;
+ return InvokeOnWorker(Bind(&BaseChannel::AddRecvStream_w, this, sp));
}
bool BaseChannel::RemoveRecvStream(uint32 ssrc) {
- SsrcMessageData data(ssrc);
- Send(MSG_REMOVERECVSTREAM, &data);
- return data.result;
+ return InvokeOnWorker(Bind(&BaseChannel::RemoveRecvStream_w, this, ssrc));
}
bool BaseChannel::AddSendStream(const StreamParams& sp) {
- StreamMessageData data(sp);
- Send(MSG_ADDSENDSTREAM, &data);
- return data.result;
+ return InvokeOnWorker(
+ Bind(&MediaChannel::AddSendStream, media_channel(), sp));
}
bool BaseChannel::RemoveSendStream(uint32 ssrc) {
- SsrcMessageData data(ssrc);
- Send(MSG_REMOVESENDSTREAM, &data);
- return data.result;
+ return InvokeOnWorker(
+ Bind(&MediaChannel::RemoveSendStream, media_channel(), ssrc));
}
bool BaseChannel::SetLocalContent(const MediaContentDescription* content,
ContentAction action,
std::string* error_desc) {
- SetContentData data(content, action, error_desc);
- Send(MSG_SETLOCALCONTENT, &data);
- return data.result;
+ return InvokeOnWorker(Bind(&BaseChannel::SetLocalContent_w,
+ this, content, action, error_desc));
}
bool BaseChannel::SetRemoteContent(const MediaContentDescription* content,
ContentAction action,
std::string* error_desc) {
- SetContentData data(content, action, error_desc);
- Send(MSG_SETREMOTECONTENT, &data);
- return data.result;
+ return InvokeOnWorker(Bind(&BaseChannel::SetRemoteContent_w,
+ this, content, action, error_desc));
}
void BaseChannel::StartConnectionMonitor(int cms) {
@@ -955,9 +709,12 @@ void BaseChannel::ChannelWritable_w() {
if (!SetupDtlsSrtp(false)) {
const std::string error_desc =
"Couldn't set up DTLS-SRTP on RTP channel.";
- SessionErrorMessageData data(BaseSession::ERROR_TRANSPORT, error_desc);
// Sent synchronously.
- signaling_thread()->Send(this, MSG_SESSION_ERROR, &data);
+ signaling_thread()->Invoke<void>(Bind(
+ &SetSessionError,
+ session_,
+ BaseSession::ERROR_TRANSPORT,
+ error_desc));
return;
}
@@ -965,9 +722,12 @@ void BaseChannel::ChannelWritable_w() {
if (!SetupDtlsSrtp(true)) {
const std::string error_desc =
"Couldn't set up DTLS-SRTP on RTCP channel";
- SessionErrorMessageData data(BaseSession::ERROR_TRANSPORT, error_desc);
// Sent synchronously.
- signaling_thread()->Send(this, MSG_SESSION_ERROR, &data);
+ signaling_thread()->Invoke<void>(Bind(
+ &SetSessionError,
+ session_,
+ BaseSession::ERROR_TRANSPORT,
+ error_desc));
return;
}
}
@@ -1217,16 +977,6 @@ bool BaseChannel::RemoveRecvStream_w(uint32 ssrc) {
return media_channel()->RemoveRecvStream(ssrc);
}
-bool BaseChannel::AddSendStream_w(const StreamParams& sp) {
- ASSERT(worker_thread() == talk_base::Thread::Current());
- return media_channel()->AddSendStream(sp);
-}
-
-bool BaseChannel::RemoveSendStream_w(uint32 ssrc) {
- ASSERT(worker_thread() == talk_base::Thread::Current());
- return media_channel()->RemoveSendStream(ssrc);
-}
-
bool BaseChannel::UpdateLocalStreams_w(const std::vector<StreamParams>& streams,
ContentAction action,
std::string* error_desc) {
@@ -1435,57 +1185,6 @@ bool BaseChannel::SetBaseRemoteContent_w(const MediaContentDescription* content,
void BaseChannel::OnMessage(talk_base::Message *pmsg) {
switch (pmsg->message_id) {
- case MSG_ENABLE:
- EnableMedia_w();
- break;
- case MSG_DISABLE:
- DisableMedia_w();
- break;
- case MSG_MUTESTREAM: {
- MuteStreamData* data = static_cast<MuteStreamData*>(pmsg->pdata);
- data->result = MuteStream_w(data->ssrc, data->mute);
- break;
- }
- case MSG_ISSTREAMMUTED: {
- SsrcMessageData* data = static_cast<SsrcMessageData*>(pmsg->pdata);
- data->result = IsStreamMuted_w(data->ssrc);
- break;
- }
- case MSG_SETLOCALCONTENT: {
- SetContentData* data = static_cast<SetContentData*>(pmsg->pdata);
- data->result = SetLocalContent_w(data->content,
- data->action,
- data->error_desc);
- break;
- }
- case MSG_SETREMOTECONTENT: {
- SetContentData* data = static_cast<SetContentData*>(pmsg->pdata);
- data->result = SetRemoteContent_w(data->content,
- data->action,
- data->error_desc);
- break;
- }
- case MSG_ADDRECVSTREAM: {
- StreamMessageData* data = static_cast<StreamMessageData*>(pmsg->pdata);
- data->result = AddRecvStream_w(data->sp);
- break;
- }
- case MSG_REMOVERECVSTREAM: {
- SsrcMessageData* data = static_cast<SsrcMessageData*>(pmsg->pdata);
- data->result = RemoveRecvStream_w(data->ssrc);
- break;
- }
- case MSG_ADDSENDSTREAM: {
- StreamMessageData* data = static_cast<StreamMessageData*>(pmsg->pdata);
- data->result = AddSendStream_w(data->sp);
- break;
- }
- case MSG_REMOVESENDSTREAM: {
- SsrcMessageData* data = static_cast<SsrcMessageData*>(pmsg->pdata);
- data->result = RemoveSendStream_w(data->ssrc);
- break;
- }
-
case MSG_RTPPACKET:
case MSG_RTCPPACKET: {
PacketMessageData* data = static_cast<PacketMessageData*>(pmsg->pdata);
@@ -1497,41 +1196,18 @@ void BaseChannel::OnMessage(talk_base::Message *pmsg) {
SignalFirstPacketReceived(this);
break;
}
- case MSG_SESSION_ERROR: {
- SessionErrorMessageData* data = static_cast<SessionErrorMessageData*>
- (pmsg->pdata);
- SetSessionError(session_, data->error_, data->error_desc_);
- break;
- }
}
}
-void BaseChannel::Send(uint32 id, talk_base::MessageData *pdata) {
- worker_thread_->Send(this, id, pdata);
-}
-
-void BaseChannel::Post(uint32 id, talk_base::MessageData *pdata) {
- worker_thread_->Post(this, id, pdata);
-}
-
-void BaseChannel::PostDelayed(int cmsDelay, uint32 id,
- talk_base::MessageData *pdata) {
- worker_thread_->PostDelayed(cmsDelay, this, id, pdata);
-}
-
-void BaseChannel::Clear(uint32 id, talk_base::MessageList* removed) {
- worker_thread_->Clear(this, id, removed);
-}
-
void BaseChannel::FlushRtcpMessages() {
// Flush all remaining RTCP messages. This should only be called in
// destructor.
ASSERT(talk_base::Thread::Current() == worker_thread_);
talk_base::MessageList rtcp_messages;
- Clear(MSG_RTCPPACKET, &rtcp_messages);
+ worker_thread_->Clear(this, MSG_RTCPPACKET, &rtcp_messages);
for (talk_base::MessageList::iterator it = rtcp_messages.begin();
it != rtcp_messages.end(); ++it) {
- Send(MSG_RTCPPACKET, it->pdata);
+ worker_thread_->Send(this, MSG_RTCPPACKET, it->pdata);
}
}
@@ -1570,21 +1246,17 @@ bool VoiceChannel::Init() {
}
bool VoiceChannel::SetRemoteRenderer(uint32 ssrc, AudioRenderer* renderer) {
- AudioRenderMessageData data(ssrc, renderer, false);
- Send(MSG_SETRENDERER, &data);
- return data.result;
+ return InvokeOnWorker(Bind(&VoiceMediaChannel::SetRemoteRenderer,
+ media_channel(), ssrc, renderer));
}
bool VoiceChannel::SetLocalRenderer(uint32 ssrc, AudioRenderer* renderer) {
- AudioRenderMessageData data(ssrc, renderer, true);
- Send(MSG_SETRENDERER, &data);
- return data.result;
+ return InvokeOnWorker(Bind(&VoiceMediaChannel::SetLocalRenderer,
+ media_channel(), ssrc, renderer));
}
bool VoiceChannel::SetRingbackTone(const void* buf, int len) {
- SetRingbackToneMessageData data(buf, len);
- Send(MSG_SETRINGBACKTONE, &data);
- return data.result;
+ return InvokeOnWorker(Bind(&VoiceChannel::SetRingbackTone_w, this, buf, len));
}
// TODO(juberti): Handle early media the right way. We should get an explicit
@@ -1595,17 +1267,17 @@ bool VoiceChannel::SetRingbackTone(const void* buf, int len) {
void VoiceChannel::SetEarlyMedia(bool enable) {
if (enable) {
// Start the early media timeout
- PostDelayed(kEarlyMediaTimeout, MSG_EARLYMEDIATIMEOUT);
+ worker_thread()->PostDelayed(kEarlyMediaTimeout, this,
+ MSG_EARLYMEDIATIMEOUT);
} else {
// Stop the timeout if currently going.
- Clear(MSG_EARLYMEDIATIMEOUT);
+ worker_thread()->Clear(this, MSG_EARLYMEDIATIMEOUT);
}
}
bool VoiceChannel::PlayRingbackTone(uint32 ssrc, bool play, bool loop) {
- PlayRingbackToneMessageData data(ssrc, play, loop);
- Send(MSG_PLAYRINGBACKTONE, &data);
- return data.result;
+ return InvokeOnWorker(Bind(&VoiceChannel::PlayRingbackTone_w,
+ this, ssrc, play, loop));
}
bool VoiceChannel::PressDTMF(int digit, bool playout) {
@@ -1618,27 +1290,24 @@ bool VoiceChannel::PressDTMF(int digit, bool playout) {
}
bool VoiceChannel::CanInsertDtmf() {
- BoolMessageData data(false);
- Send(MSG_CANINSERTDTMF, &data);
- return data.data();
+ return InvokeOnWorker(Bind(&VoiceMediaChannel::CanInsertDtmf,
+ media_channel()));
}
bool VoiceChannel::InsertDtmf(uint32 ssrc, int event_code, int duration,
int flags) {
- DtmfMessageData data(ssrc, event_code, duration, flags);
- Send(MSG_INSERTDTMF, &data);
- return data.result;
+ return InvokeOnWorker(Bind(&VoiceChannel::InsertDtmf_w, this,
+ ssrc, event_code, duration, flags));
}
bool VoiceChannel::SetOutputScaling(uint32 ssrc, double left, double right) {
- ScaleVolumeMessageData data(ssrc, left, right);
- Send(MSG_SCALEVOLUME, &data);
- return data.result;
+ return InvokeOnWorker(Bind(&VoiceMediaChannel::SetOutputScaling,
+ media_channel(), ssrc, left, right));
}
+
bool VoiceChannel::GetStats(VoiceMediaInfo* stats) {
- VoiceStatsMessageData data(stats);
- Send(MSG_GETSTATS, &data);
- return data.result;
+ return InvokeOnWorker(Bind(&VoiceMediaChannel::GetStats,
+ media_channel(), stats));
}
void VoiceChannel::StartMediaMonitor(int cms) {
@@ -1855,10 +1524,6 @@ void VoiceChannel::HandleEarlyMediaTimeout() {
}
}
-bool VoiceChannel::CanInsertDtmf_w() {
- return media_channel()->CanInsertDtmf();
-}
-
bool VoiceChannel::InsertDtmf_w(uint32 ssrc, int event, int duration,
int flags) {
if (!enabled()) {
@@ -1868,74 +1533,16 @@ bool VoiceChannel::InsertDtmf_w(uint32 ssrc, int event, int duration,
return media_channel()->InsertDtmf(ssrc, event, duration, flags);
}
-bool VoiceChannel::SetOutputScaling_w(uint32 ssrc, double left, double right) {
- return media_channel()->SetOutputScaling(ssrc, left, right);
-}
-
-bool VoiceChannel::GetStats_w(VoiceMediaInfo* stats) {
- return media_channel()->GetStats(stats);
-}
-
bool VoiceChannel::SetChannelOptions(const AudioOptions& options) {
- AudioOptionsMessageData data(options);
- Send(MSG_SETCHANNELOPTIONS, &data);
- return data.result;
-}
-
-bool VoiceChannel::SetChannelOptions_w(const AudioOptions& options) {
- return media_channel()->SetOptions(options);
-}
-
-bool VoiceChannel::SetRenderer_w(uint32 ssrc, AudioRenderer* renderer,
- bool is_local) {
- if (is_local)
- return media_channel()->SetLocalRenderer(ssrc, renderer);
-
- return media_channel()->SetRemoteRenderer(ssrc, renderer);
+ return InvokeOnWorker(Bind(&VoiceMediaChannel::SetOptions,
+ media_channel(), options));
}
void VoiceChannel::OnMessage(talk_base::Message *pmsg) {
switch (pmsg->message_id) {
- case MSG_SETRINGBACKTONE: {
- SetRingbackToneMessageData* data =
- static_cast<SetRingbackToneMessageData*>(pmsg->pdata);
- data->result = SetRingbackTone_w(data->buf, data->len);
- break;
- }
- case MSG_PLAYRINGBACKTONE: {
- PlayRingbackToneMessageData* data =
- static_cast<PlayRingbackToneMessageData*>(pmsg->pdata);
- data->result = PlayRingbackTone_w(data->ssrc, data->play, data->loop);
- break;
- }
case MSG_EARLYMEDIATIMEOUT:
HandleEarlyMediaTimeout();
break;
- case MSG_CANINSERTDTMF: {
- BoolMessageData* data =
- static_cast<BoolMessageData*>(pmsg->pdata);
- data->data() = CanInsertDtmf_w();
- break;
- }
- case MSG_INSERTDTMF: {
- DtmfMessageData* data =
- static_cast<DtmfMessageData*>(pmsg->pdata);
- data->result = InsertDtmf_w(data->ssrc, data->event, data->duration,
- data->flags);
- break;
- }
- case MSG_SCALEVOLUME: {
- ScaleVolumeMessageData* data =
- static_cast<ScaleVolumeMessageData*>(pmsg->pdata);
- data->result = SetOutputScaling_w(data->ssrc, data->left, data->right);
- break;
- }
- case MSG_GETSTATS: {
- VoiceStatsMessageData* data =
- static_cast<VoiceStatsMessageData*>(pmsg->pdata);
- data->result = GetStats_w(data->stats);
- break;
- }
case MSG_CHANNEL_ERROR: {
VoiceChannelErrorMessageData* data =
static_cast<VoiceChannelErrorMessageData*>(pmsg->pdata);
@@ -1943,18 +1550,6 @@ void VoiceChannel::OnMessage(talk_base::Message *pmsg) {
delete data;
break;
}
- case MSG_SETCHANNELOPTIONS: {
- AudioOptionsMessageData* data =
- static_cast<AudioOptionsMessageData*>(pmsg->pdata);
- data->result = SetChannelOptions_w(data->options);
- break;
- }
- case MSG_SETRENDERER: {
- AudioRenderMessageData* data =
- static_cast<AudioRenderMessageData*>(pmsg->pdata);
- data->result = SetRenderer_w(data->ssrc, data->renderer, data->is_local);
- break;
- }
default:
BaseChannel::OnMessage(pmsg);
break;
@@ -2068,68 +1663,65 @@ VideoChannel::~VideoChannel() {
}
bool VideoChannel::SetRenderer(uint32 ssrc, VideoRenderer* renderer) {
- VideoRenderMessageData data(ssrc, renderer);
- Send(MSG_SETRENDERER, &data);
+ worker_thread()->Invoke<void>(Bind(
+ &VideoMediaChannel::SetRenderer, media_channel(), ssrc, renderer));
return true;
}
bool VideoChannel::ApplyViewRequest(const ViewRequest& request) {
- ViewRequestMessageData data(request);
- Send(MSG_HANDLEVIEWREQUEST, &data);
- return data.result;
+ return InvokeOnWorker(Bind(&VideoChannel::ApplyViewRequest_w, this, request));
}
VideoCapturer* VideoChannel::AddScreencast(
uint32 ssrc, const ScreencastId& id) {
- AddScreencastMessageData data(ssrc, id);
- Send(MSG_ADDSCREENCAST, &data);
- return data.result;
+ return worker_thread()->Invoke<VideoCapturer*>(Bind(
+ &VideoChannel::AddScreencast_w, this, ssrc, id));
}
bool VideoChannel::SetCapturer(uint32 ssrc, VideoCapturer* capturer) {
- SetCapturerMessageData data(ssrc, capturer);
- Send(MSG_SETCAPTURER, &data);
- return data.result;
+ return InvokeOnWorker(Bind(&VideoMediaChannel::SetCapturer,
+ media_channel(), ssrc, capturer));
}
bool VideoChannel::RemoveScreencast(uint32 ssrc) {
- RemoveScreencastMessageData data(ssrc);
- Send(MSG_REMOVESCREENCAST, &data);
- return data.result;
+ return InvokeOnWorker(Bind(&VideoChannel::RemoveScreencast_w, this, ssrc));
}
bool VideoChannel::IsScreencasting() {
- IsScreencastingMessageData data;
- Send(MSG_ISSCREENCASTING, &data);
- return data.result;
+ return InvokeOnWorker(Bind(&VideoChannel::IsScreencasting_w, this));
}
int VideoChannel::GetScreencastFps(uint32 ssrc) {
- ScreencastDetailsMessageData data(ssrc);
- Send(MSG_GETSCREENCASTDETAILS, &data);
+ ScreencastDetailsData data(ssrc);
+ worker_thread()->Invoke<void>(Bind(
+ &VideoChannel::GetScreencastDetails_w, this, &data));
return data.fps;
}
int VideoChannel::GetScreencastMaxPixels(uint32 ssrc) {
- ScreencastDetailsMessageData data(ssrc);
- Send(MSG_GETSCREENCASTDETAILS, &data);
+ ScreencastDetailsData data(ssrc);
+ worker_thread()->Invoke<void>(Bind(
+ &VideoChannel::GetScreencastDetails_w, this, &data));
return data.screencast_max_pixels;
}
bool VideoChannel::SendIntraFrame() {
- Send(MSG_SENDINTRAFRAME);
+ worker_thread()->Invoke<void>(Bind(
+ &VideoMediaChannel::SendIntraFrame, media_channel()));
return true;
}
bool VideoChannel::RequestIntraFrame() {
- Send(MSG_REQUESTINTRAFRAME);
+ worker_thread()->Invoke<void>(Bind(
+ &VideoMediaChannel::RequestIntraFrame, media_channel()));
return true;
}
void VideoChannel::SetScreenCaptureFactory(
ScreenCapturerFactory* screencapture_factory) {
- SetScreenCaptureFactoryMessageData data(screencapture_factory);
- Send(MSG_SETSCREENCASTFACTORY, &data);
+ worker_thread()->Invoke<void>(Bind(
+ &VideoChannel::SetScreenCaptureFactory_w,
+ this, screencapture_factory));
}
void VideoChannel::ChangeState() {
@@ -2153,9 +1745,8 @@ void VideoChannel::ChangeState() {
}
bool VideoChannel::GetStats(VideoMediaInfo* stats) {
- VideoStatsMessageData data(stats);
- Send(MSG_GETSTATS, &data);
- return data.result;
+ return InvokeOnWorker(Bind(&VideoMediaChannel::GetStats,
+ media_channel(), stats));
}
void VideoChannel::StartMediaMonitor(int cms) {
@@ -2307,10 +1898,6 @@ bool VideoChannel::ApplyViewRequest_w(const ViewRequest& request) {
return ret;
}
-void VideoChannel::SetRenderer_w(uint32 ssrc, VideoRenderer* renderer) {
- media_channel()->SetRenderer(ssrc, renderer);
-}
-
VideoCapturer* VideoChannel::AddScreencast_w(
uint32 ssrc, const ScreencastId& id) {
if (screencast_capturers_.find(ssrc) != screencast_capturers_.end()) {
@@ -2327,10 +1914,6 @@ VideoCapturer* VideoChannel::AddScreencast_w(
return screen_capturer;
}
-bool VideoChannel::SetCapturer_w(uint32 ssrc, VideoCapturer* capturer) {
- return media_channel()->SetCapturer(ssrc, capturer);
-}
-
bool VideoChannel::RemoveScreencast_w(uint32 ssrc) {
ScreencastMap::iterator iter = screencast_capturers_.find(ssrc);
if (iter == screencast_capturers_.end()) {
@@ -2346,8 +1929,8 @@ bool VideoChannel::IsScreencasting_w() const {
return !screencast_capturers_.empty();
}
-void VideoChannel::ScreencastDetails_w(
- ScreencastDetailsMessageData* data) const {
+void VideoChannel::GetScreencastDetails_w(
+ ScreencastDetailsData* data) const {
ScreencastMap::const_iterator iter = screencast_capturers_.find(data->ssrc);
if (iter == screencast_capturers_.end()) {
return;
@@ -2367,10 +1950,6 @@ void VideoChannel::SetScreenCaptureFactory_w(
}
}
-bool VideoChannel::GetStats_w(VideoMediaInfo* stats) {
- return media_channel()->GetStats(stats);
-}
-
void VideoChannel::OnScreencastWindowEvent_s(uint32 ssrc,
talk_base::WindowEvent we) {
ASSERT(signaling_thread() == talk_base::Thread::Current());
@@ -2378,41 +1957,12 @@ void VideoChannel::OnScreencastWindowEvent_s(uint32 ssrc,
}
bool VideoChannel::SetChannelOptions(const VideoOptions &options) {
- VideoOptionsMessageData data(options);
- Send(MSG_SETCHANNELOPTIONS, &data);
- return data.result;
-}
-
-bool VideoChannel::SetChannelOptions_w(const VideoOptions &options) {
- return media_channel()->SetOptions(options);
+ return InvokeOnWorker(Bind(&VideoMediaChannel::SetOptions,
+ media_channel(), options));
}
void VideoChannel::OnMessage(talk_base::Message *pmsg) {
switch (pmsg->message_id) {
- case MSG_SETRENDERER: {
- const VideoRenderMessageData* data =
- static_cast<VideoRenderMessageData*>(pmsg->pdata);
- SetRenderer_w(data->ssrc, data->renderer);
- break;
- }
- case MSG_ADDSCREENCAST: {
- AddScreencastMessageData* data =
- static_cast<AddScreencastMessageData*>(pmsg->pdata);
- data->result = AddScreencast_w(data->ssrc, data->window_id);
- break;
- }
- case MSG_SETCAPTURER: {
- SetCapturerMessageData* data =
- static_cast<SetCapturerMessageData*>(pmsg->pdata);
- data->result = SetCapturer_w(data->ssrc, data->capturer);
- break;
- }
- case MSG_REMOVESCREENCAST: {
- RemoveScreencastMessageData* data =
- static_cast<RemoveScreencastMessageData*>(pmsg->pdata);
- data->result = RemoveScreencast_w(data->ssrc);
- break;
- }
case MSG_SCREENCASTWINDOWEVENT: {
const ScreencastEventMessageData* data =
static_cast<ScreencastEventMessageData*>(pmsg->pdata);
@@ -2420,32 +1970,6 @@ void VideoChannel::OnMessage(talk_base::Message *pmsg) {
delete data;
break;
}
- case MSG_ISSCREENCASTING: {
- IsScreencastingMessageData* data =
- static_cast<IsScreencastingMessageData*>(pmsg->pdata);
- data->result = IsScreencasting_w();
- break;
- }
- case MSG_GETSCREENCASTDETAILS: {
- ScreencastDetailsMessageData* data =
- static_cast<ScreencastDetailsMessageData*>(pmsg->pdata);
- ScreencastDetails_w(data);
- break;
- }
- case MSG_SENDINTRAFRAME: {
- SendIntraFrame_w();
- break;
- }
- case MSG_REQUESTINTRAFRAME: {
- RequestIntraFrame_w();
- break;
- }
- case MSG_SETCHANNELOPTIONS: {
- VideoOptionsMessageData* data =
- static_cast<VideoOptionsMessageData*>(pmsg->pdata);
- data->result = SetChannelOptions_w(data->options);
- break;
- }
case MSG_CHANNEL_ERROR: {
const VideoChannelErrorMessageData* data =
static_cast<VideoChannelErrorMessageData*>(pmsg->pdata);
@@ -2453,24 +1977,6 @@ void VideoChannel::OnMessage(talk_base::Message *pmsg) {
delete data;
break;
}
- case MSG_HANDLEVIEWREQUEST: {
- ViewRequestMessageData* data =
- static_cast<ViewRequestMessageData*>(pmsg->pdata);
- data->result = ApplyViewRequest_w(data->request);
- break;
- }
- case MSG_SETSCREENCASTFACTORY: {
- SetScreenCaptureFactoryMessageData* data =
- static_cast<SetScreenCaptureFactoryMessageData*>(pmsg->pdata);
- SetScreenCaptureFactory_w(data->screencapture_factory);
- break;
- }
- case MSG_GETSTATS: {
- VideoStatsMessageData* data =
- static_cast<VideoStatsMessageData*>(pmsg->pdata);
- data->result = GetStats_w(data->stats);
- break;
- }
default:
BaseChannel::OnMessage(pmsg);
break;
@@ -2516,9 +2022,8 @@ void VideoChannel::OnStateChange(VideoCapturer* capturer, CaptureState ev) {
if (!GetLocalSsrc(capturer, &ssrc)) {
return;
}
- ScreencastEventMessageData* pdata =
- new ScreencastEventMessageData(ssrc, we);
- signaling_thread()->Post(this, MSG_SCREENCASTWINDOWEVENT, pdata);
+
+ OnScreencastWindowEvent(ssrc, we);
}
bool VideoChannel::GetLocalSsrc(const VideoCapturer* capturer, uint32* ssrc) {
@@ -2611,9 +2116,8 @@ bool DataChannel::Init() {
bool DataChannel::SendData(const SendDataParams& params,
const talk_base::Buffer& payload,
SendDataResult* result) {
- SendDataMessageData message_data(params, &payload, result);
- Send(MSG_SENDDATA, &message_data);
- return message_data.succeeded;
+ return InvokeOnWorker(Bind(&DataMediaChannel::SendData,
+ media_channel(), params, payload, result));
}
const ContentInfo* DataChannel::GetFirstContent(
@@ -2810,9 +2314,8 @@ void DataChannel::ChangeState() {
LOG(LS_ERROR) << "Failed to SetSend on data channel";
}
- // Post to trigger SignalReadyToSendData.
- signaling_thread()->Post(this, MSG_READYTOSENDDATA,
- new DataChannelReadyToSendMessageData(send));
+ // Trigger SignalReadyToSendData asynchronously.
+ OnDataChannelReadyToSend(send);
LOG(LS_INFO) << "Changing data state, recv=" << recv << " send=" << send;
}
@@ -2827,13 +2330,6 @@ void DataChannel::OnMessage(talk_base::Message *pmsg) {
delete data;
break;
}
- case MSG_SENDDATA: {
- SendDataMessageData* msg =
- static_cast<SendDataMessageData*>(pmsg->pdata);
- msg->succeeded = media_channel()->SendData(
- msg->params, *(msg->payload), msg->result);
- break;
- }
case MSG_DATARECEIVED: {
DataReceivedMessageData* data =
static_cast<DataReceivedMessageData*>(pmsg->pdata);
diff --git a/talk/session/media/channel.h b/talk/session/media/channel.h
index 91ea6222d4..f3793cbd2d 100644
--- a/talk/session/media/channel.h
+++ b/talk/session/media/channel.h
@@ -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_;