Update libjingle to 61168196
R=mallinath@webrtc.org Review URL: https://webrtc-codereview.appspot.com/8139004 git-svn-id: http://webrtc.googlecode.com/svn/trunk@5502 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
parent
9510e53cc0
commit
9cf037b831
@ -668,7 +668,7 @@ public class PeerConnectionTest extends TestCase {
|
||||
offeringExpectations.expectMessage(expectedBinaryMessage, true);
|
||||
assertTrue(answeringExpectations.dataChannel.send(
|
||||
new DataChannel.Buffer(
|
||||
ByteBuffer.wrap(new byte[] { 1, 2, 3, 4, 5 } ), true)));
|
||||
ByteBuffer.wrap(new byte[] { 1, 2, 3, 4, 5 }), true)));
|
||||
offeringExpectations.waitForAllExpectationsToBeSatisfied();
|
||||
|
||||
offeringExpectations.expectStateChange(DataChannel.State.CLOSING);
|
||||
|
@ -70,6 +70,9 @@ bool FromConstraints(const MediaConstraintsInterface::Constraints& constraints,
|
||||
options->experimental_agc.Set(value);
|
||||
else if (iter->key == MediaConstraintsInterface::kNoiseSuppression)
|
||||
options->noise_suppression.Set(value);
|
||||
else if (iter->key ==
|
||||
MediaConstraintsInterface::kExperimentalNoiseSuppression)
|
||||
options->experimental_ns.Set(value);
|
||||
else if (iter->key == MediaConstraintsInterface::kHighpassFilter)
|
||||
options->highpass_filter.Set(value);
|
||||
else if (iter->key == MediaConstraintsInterface::kTypingNoiseDetection)
|
||||
|
@ -56,6 +56,8 @@ const char MediaConstraintsInterface::kExperimentalAutoGainControl[] =
|
||||
"googAutoGainControl2";
|
||||
const char MediaConstraintsInterface::kNoiseSuppression[] =
|
||||
"googNoiseSuppression";
|
||||
const char MediaConstraintsInterface::kExperimentalNoiseSuppression[] =
|
||||
"googNoiseSuppression2";
|
||||
const char MediaConstraintsInterface::kHighpassFilter[] =
|
||||
"googHighpassFilter";
|
||||
const char MediaConstraintsInterface::kTypingNoiseDetection[] =
|
||||
|
@ -79,6 +79,7 @@ class MediaConstraintsInterface {
|
||||
static const char kAutoGainControl[]; // googAutoGainControl
|
||||
static const char kExperimentalAutoGainControl[]; // googAutoGainControl2
|
||||
static const char kNoiseSuppression[]; // googNoiseSuppression
|
||||
static const char kExperimentalNoiseSuppression[]; // googNoiseSuppression2
|
||||
static const char kHighpassFilter[]; // googHighpassFilter
|
||||
static const char kTypingNoiseDetection[]; // googTypingNoiseDetection
|
||||
static const char kAudioMirroring[]; // googAudioMirroring
|
||||
|
@ -114,7 +114,7 @@ void LocalAudioTrackHandler::OnEnabledChanged() {
|
||||
// adapter owned by this class.
|
||||
cricket::AudioRenderer* renderer = audio_track_->GetRenderer() ?
|
||||
audio_track_->GetRenderer() : sink_adapter_.get();
|
||||
ASSERT(renderer);
|
||||
ASSERT(renderer != NULL);
|
||||
provider_->SetAudioSend(ssrc(), audio_track_->enabled(), options, renderer);
|
||||
}
|
||||
|
||||
|
@ -1269,7 +1269,12 @@ TEST_F(JsepPeerConnectionP2PTestClient, GetBytesSentStats) {
|
||||
}
|
||||
|
||||
// This test sets up a call between two parties with audio, video and data.
|
||||
// TODO(jiayl): fix the flakiness on Windows and reenable. Issue 2891.
|
||||
#if defined(WIN32)
|
||||
TEST_F(JsepPeerConnectionP2PTestClient, DISABLED_LocalP2PTestDataChannel) {
|
||||
#else
|
||||
TEST_F(JsepPeerConnectionP2PTestClient, LocalP2PTestDataChannel) {
|
||||
#endif
|
||||
FakeConstraints setup_constraints;
|
||||
setup_constraints.SetAllowRtpDataChannels();
|
||||
ASSERT_TRUE(CreateTestClients(&setup_constraints, &setup_constraints));
|
||||
|
@ -83,6 +83,8 @@ const char StatsReport::kStatsValueNameFingerprintAlgorithm[] =
|
||||
"googFingerprintAlgorithm";
|
||||
const char StatsReport::kStatsValueNameFirsReceived[] = "googFirsReceived";
|
||||
const char StatsReport::kStatsValueNameFirsSent[] = "googFirsSent";
|
||||
const char StatsReport::kStatsValueNameFrameHeightInput[] =
|
||||
"googFrameHeightInput";
|
||||
const char StatsReport::kStatsValueNameFrameHeightReceived[] =
|
||||
"googFrameHeightReceived";
|
||||
const char StatsReport::kStatsValueNameFrameHeightSent[] =
|
||||
@ -104,6 +106,8 @@ const char StatsReport::kStatsValueNameRenderDelayMs[] = "googRenderDelayMs";
|
||||
|
||||
const char StatsReport::kStatsValueNameFrameRateInput[] = "googFrameRateInput";
|
||||
const char StatsReport::kStatsValueNameFrameRateSent[] = "googFrameRateSent";
|
||||
const char StatsReport::kStatsValueNameFrameWidthInput[] =
|
||||
"googFrameWidthInput";
|
||||
const char StatsReport::kStatsValueNameFrameWidthReceived[] =
|
||||
"googFrameWidthReceived";
|
||||
const char StatsReport::kStatsValueNameFrameWidthSent[] = "googFrameWidthSent";
|
||||
@ -117,6 +121,8 @@ const char StatsReport::kStatsValueNameLocalCertificateId[] =
|
||||
"googLocalCertificateId";
|
||||
const char StatsReport::kStatsValueNameNacksReceived[] = "googNacksReceived";
|
||||
const char StatsReport::kStatsValueNameNacksSent[] = "googNacksSent";
|
||||
const char StatsReport::kStatsValueNameNetEqExpandRate[] =
|
||||
"googNetEqExpandRate";
|
||||
const char StatsReport::kStatsValueNamePacketsReceived[] = "packetsReceived";
|
||||
const char StatsReport::kStatsValueNamePacketsSent[] = "packetsSent";
|
||||
const char StatsReport::kStatsValueNamePacketsLost[] = "packetsLost";
|
||||
@ -215,6 +221,8 @@ void ExtractStats(const cricket::VoiceReceiverInfo& info, StatsReport* report) {
|
||||
info.bytes_rcvd);
|
||||
report->AddValue(StatsReport::kStatsValueNameJitterReceived,
|
||||
info.jitter_ms);
|
||||
report->AddValue(StatsReport::kStatsValueNameNetEqExpandRate,
|
||||
talk_base::ToString<float>(info.expand_rate));
|
||||
report->AddValue(StatsReport::kStatsValueNamePacketsReceived,
|
||||
info.packets_rcvd);
|
||||
report->AddValue(StatsReport::kStatsValueNamePacketsLost,
|
||||
@ -295,10 +303,14 @@ void ExtractStats(const cricket::VideoSenderInfo& info, StatsReport* report) {
|
||||
info.firs_rcvd);
|
||||
report->AddValue(StatsReport::kStatsValueNameNacksReceived,
|
||||
info.nacks_rcvd);
|
||||
report->AddValue(StatsReport::kStatsValueNameFrameWidthInput,
|
||||
info.input_frame_width);
|
||||
report->AddValue(StatsReport::kStatsValueNameFrameHeightInput,
|
||||
info.input_frame_height);
|
||||
report->AddValue(StatsReport::kStatsValueNameFrameWidthSent,
|
||||
info.frame_width);
|
||||
info.send_frame_width);
|
||||
report->AddValue(StatsReport::kStatsValueNameFrameHeightSent,
|
||||
info.frame_height);
|
||||
info.send_frame_height);
|
||||
report->AddValue(StatsReport::kStatsValueNameFrameRateInput,
|
||||
info.framerate_input);
|
||||
report->AddValue(StatsReport::kStatsValueNameFrameRateSent,
|
||||
|
@ -143,6 +143,7 @@ class StatsReport {
|
||||
static const char kStatsValueNameEchoReturnLossEnhancement[];
|
||||
static const char kStatsValueNameFirsReceived[];
|
||||
static const char kStatsValueNameFirsSent[];
|
||||
static const char kStatsValueNameFrameHeightInput[];
|
||||
static const char kStatsValueNameFrameHeightReceived[];
|
||||
static const char kStatsValueNameFrameHeightSent[];
|
||||
static const char kStatsValueNameFrameRateReceived[];
|
||||
@ -157,11 +158,13 @@ class StatsReport {
|
||||
static const char kStatsValueNameRenderDelayMs[];
|
||||
static const char kStatsValueNameFrameRateInput[];
|
||||
static const char kStatsValueNameFrameRateSent[];
|
||||
static const char kStatsValueNameFrameWidthInput[];
|
||||
static const char kStatsValueNameFrameWidthReceived[];
|
||||
static const char kStatsValueNameFrameWidthSent[];
|
||||
static const char kStatsValueNameJitterReceived[];
|
||||
static const char kStatsValueNameNacksReceived[];
|
||||
static const char kStatsValueNameNacksSent[];
|
||||
static const char kStatsValueNameNetEqExpandRate[];
|
||||
static const char kStatsValueNameRtt[];
|
||||
static const char kStatsValueNameAvailableSendBandwidth[];
|
||||
static const char kStatsValueNameAvailableReceiveBandwidth[];
|
||||
|
101
talk/base/asyncinvoker-inl.h
Normal file
101
talk/base/asyncinvoker-inl.h
Normal file
@ -0,0 +1,101 @@
|
||||
/*
|
||||
* libjingle
|
||||
* Copyright 2014 Google Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef TALK_BASE_ASYNCINVOKER_INL_H_
|
||||
#define TALK_BASE_ASYNCINVOKER_INL_H_
|
||||
|
||||
#include "talk/base/criticalsection.h"
|
||||
#include "talk/base/messagehandler.h"
|
||||
#include "talk/base/sigslot.h"
|
||||
#include "talk/base/thread.h"
|
||||
|
||||
namespace talk_base {
|
||||
|
||||
// Helper class for AsyncInvoker. Runs a functor on a message queue or thread
|
||||
// and doesn't execute the callback when finished if the calling thread ends.
|
||||
template <class ReturnT, class FunctorT>
|
||||
class AsyncFunctorMessageHandler
|
||||
: public FunctorMessageHandler<ReturnT, FunctorT>,
|
||||
public sigslot::has_slots<> {
|
||||
typedef AsyncFunctorMessageHandler<ReturnT, FunctorT> ThisT;
|
||||
public:
|
||||
explicit AsyncFunctorMessageHandler(const FunctorT& functor)
|
||||
: FunctorMessageHandler<ReturnT, FunctorT>(functor),
|
||||
thread_(Thread::Current()),
|
||||
shutting_down_(false) {
|
||||
thread_->SignalQueueDestroyed.connect(this, &ThisT::OnThreadDestroyed);
|
||||
}
|
||||
|
||||
virtual ~AsyncFunctorMessageHandler() {
|
||||
CritScope cs(&running_crit_);
|
||||
shutting_down_ = true;
|
||||
}
|
||||
|
||||
virtual void OnMessage(Message* msg) {
|
||||
CritScope cs(&running_crit_);
|
||||
if (!shutting_down_) {
|
||||
FunctorMessageHandler<ReturnT, FunctorT>::OnMessage(msg);
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the thread that initiated the async call.
|
||||
Thread* thread() const { return thread_; }
|
||||
|
||||
// Wraps a callback so that it won't execute if |thread_| goes away.
|
||||
void WrapCallback(Callback0<void> cb) {
|
||||
this->SetCallback(
|
||||
Callback0<void>(Bind(&ThisT::MaybeRunCallback, this, cb)));
|
||||
}
|
||||
|
||||
private:
|
||||
void OnThreadDestroyed() {
|
||||
CritScope cs(&thread_crit_);
|
||||
thread_ = NULL;
|
||||
this->SetCallback(Callback0<void>()); // Clear out the callback.
|
||||
}
|
||||
|
||||
void MaybeRunCallback(Callback0<void> cb) {
|
||||
#ifdef _DEBUG
|
||||
ASSERT(running_crit_.CurrentThreadIsOwner());
|
||||
#endif
|
||||
CritScope cs(&thread_crit_);
|
||||
if (thread_ && !shutting_down_) {
|
||||
cb();
|
||||
}
|
||||
}
|
||||
|
||||
FunctorT functor_;
|
||||
Thread* thread_;
|
||||
CriticalSection thread_crit_;
|
||||
CriticalSection running_crit_;
|
||||
bool shutting_down_;
|
||||
};
|
||||
|
||||
} // namespace talk_base
|
||||
|
||||
|
||||
#endif // TALK_BASE_ASYNCINVOKER_INL_H_
|
78
talk/base/asyncinvoker.cc
Normal file
78
talk/base/asyncinvoker.cc
Normal file
@ -0,0 +1,78 @@
|
||||
/*
|
||||
* libjingle
|
||||
* Copyright 2014 Google Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "talk/base/asyncinvoker.h"
|
||||
|
||||
namespace talk_base {
|
||||
|
||||
// Synchronously execute all outstanding calls we own pending
|
||||
// on |thread|. Optionally filter by message id.
|
||||
void AsyncInvoker::Flush(Thread* thread, uint32 id /*= MQID_ANY*/) {
|
||||
// Run this on |thread| to reduce the number of context switches.
|
||||
if (Thread::Current() != thread) {
|
||||
thread->Invoke<void>(Bind(&AsyncInvoker::Flush, this, thread, id));
|
||||
return;
|
||||
}
|
||||
|
||||
// Make a copy of handlers_, since it'll be modified by
|
||||
// callbacks to RemoveHandler when each is done executing.
|
||||
crit_.Enter();
|
||||
std::vector<MessageHandler*> handlers(handlers_.collection());
|
||||
crit_.Leave();
|
||||
MessageList removed;
|
||||
for (size_t i = 0; i < handlers.size(); ++i) {
|
||||
removed.clear();
|
||||
thread->Clear(handlers[i], id, &removed);
|
||||
if (!removed.empty()) {
|
||||
// Since each message gets its own handler with AsyncInvoker,
|
||||
// we expect a maximum of one removed.
|
||||
ASSERT(removed.size() == 1);
|
||||
// This handler was pending on this thread, so run it now.
|
||||
const Message& msg = removed.front();
|
||||
thread->Send(msg.phandler,
|
||||
msg.message_id,
|
||||
msg.pdata);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AsyncInvoker::InvokeHandler(Thread* thread, MessageHandler* handler,
|
||||
uint32 id) {
|
||||
{
|
||||
CritScope cs(&crit_);
|
||||
handlers_.PushBack(handler);
|
||||
}
|
||||
thread->Post(handler, id);
|
||||
}
|
||||
|
||||
void AsyncInvoker::RemoveHandler(MessageHandler* handler) {
|
||||
CritScope cs(&crit_);
|
||||
handlers_.Remove(handler);
|
||||
delete handler;
|
||||
}
|
||||
|
||||
} // namespace talk_base
|
167
talk/base/asyncinvoker.h
Normal file
167
talk/base/asyncinvoker.h
Normal file
@ -0,0 +1,167 @@
|
||||
/*
|
||||
* libjingle
|
||||
* Copyright 2014 Google Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef TALK_BASE_ASYNCINVOKER_H_
|
||||
#define TALK_BASE_ASYNCINVOKER_H_
|
||||
|
||||
#include "talk/base/asyncinvoker-inl.h"
|
||||
#include "talk/base/bind.h"
|
||||
#include "talk/base/scopedptrcollection.h"
|
||||
#include "talk/base/thread.h"
|
||||
|
||||
namespace talk_base {
|
||||
|
||||
// Invokes function objects (aka functors) asynchronously on a Thread, and
|
||||
// owns the lifetime of calls (ie, when this object is destroyed, calls in
|
||||
// flight are cancelled). AsyncInvoker can optionally execute a user-specified
|
||||
// function when the asynchronous call is complete, or operates in
|
||||
// fire-and-forget mode otherwise.
|
||||
//
|
||||
// AsyncInvoker does not own the thread it calls functors on.
|
||||
//
|
||||
// A note about async calls and object lifetimes: users should
|
||||
// be mindful of object lifetimes when calling functions asynchronously and
|
||||
// ensure objects used by the function _cannot_ be deleted between the
|
||||
// invocation and execution of the functor. AsyncInvoker is designed to
|
||||
// help: any calls in flight will be cancelled when the AsyncInvoker used to
|
||||
// make the call is destructed, and any calls executing will be allowed to
|
||||
// complete before AsyncInvoker destructs.
|
||||
//
|
||||
// The easiest way to ensure lifetimes are handled correctly is to create a
|
||||
// class that owns the Thread and AsyncInvoker objects, and then call its
|
||||
// methods asynchronously as needed.
|
||||
//
|
||||
// Example:
|
||||
// class MyClass {
|
||||
// public:
|
||||
// void FireAsyncTaskWithResult(Thread* thread, int x) {
|
||||
// // Specify a callback to get the result upon completion.
|
||||
// invoker_.AsyncInvoke<int>(
|
||||
// thread, Bind(&MyClass::AsyncTaskWithResult, this, x),
|
||||
// &MyClass::OnTaskComplete, this);
|
||||
// }
|
||||
// void FireAnotherAsyncTask(Thread* thread) {
|
||||
// // No callback specified means fire-and-forget.
|
||||
// invoker_.AsyncInvoke<void>(
|
||||
// thread, Bind(&MyClass::AnotherAsyncTask, this));
|
||||
//
|
||||
// private:
|
||||
// int AsyncTaskWithResult(int x) {
|
||||
// // Some long running process...
|
||||
// return x * x;
|
||||
// }
|
||||
// void AnotherAsyncTask() {
|
||||
// // Some other long running process...
|
||||
// }
|
||||
// void OnTaskComplete(int result) { result_ = result; }
|
||||
//
|
||||
// AsyncInvoker invoker_;
|
||||
// int result_;
|
||||
// };
|
||||
class AsyncInvoker {
|
||||
public:
|
||||
// Call |functor| asynchronously on |thread|, with no callback upon
|
||||
// completion. Returns immediately.
|
||||
template <class ReturnT, class FunctorT>
|
||||
void AsyncInvoke(Thread* thread,
|
||||
const FunctorT& functor,
|
||||
uint32 id = 0) {
|
||||
FunctorMessageHandler<ReturnT, FunctorT>* handler =
|
||||
new FunctorMessageHandler<ReturnT, FunctorT>(functor);
|
||||
handler->SetCallback(Bind(&AsyncInvoker::RemoveHandler, this, handler));
|
||||
InvokeHandler(thread, handler, id);
|
||||
}
|
||||
|
||||
// Call |functor| asynchronously on |thread|, calling |callback| when done.
|
||||
template <class ReturnT, class FunctorT, class HostT>
|
||||
void AsyncInvoke(Thread* thread,
|
||||
const FunctorT& functor,
|
||||
void (HostT::*callback)(ReturnT),
|
||||
HostT* callback_host,
|
||||
uint32 id = 0) {
|
||||
AsyncFunctorMessageHandler<ReturnT, FunctorT>* handler =
|
||||
new AsyncFunctorMessageHandler<ReturnT, FunctorT>(functor);
|
||||
handler->WrapCallback(
|
||||
Bind(&AsyncInvoker::OnAsyncCallCompleted<ReturnT, FunctorT, HostT>,
|
||||
this, handler, callback, callback_host));
|
||||
InvokeHandler(thread, handler, id);
|
||||
}
|
||||
|
||||
// Call |functor| asynchronously on |thread|, calling |callback| when done.
|
||||
// Overloaded for void return.
|
||||
template <class ReturnT, class FunctorT, class HostT>
|
||||
void AsyncInvoke(Thread* thread,
|
||||
const FunctorT& functor,
|
||||
void (HostT::*callback)(),
|
||||
HostT* callback_host,
|
||||
uint32 id = 0) {
|
||||
AsyncFunctorMessageHandler<void, FunctorT>* handler =
|
||||
new AsyncFunctorMessageHandler<ReturnT, FunctorT>(functor);
|
||||
handler->WrapCallback(
|
||||
Bind(&AsyncInvoker::OnAsyncVoidCallCompleted<FunctorT, HostT>,
|
||||
this, handler, callback, callback_host));
|
||||
InvokeHandler(thread, handler, id);
|
||||
}
|
||||
|
||||
// Synchronously execute on |thread| all outstanding calls we own
|
||||
// that are pending on |thread|, and wait for calls to complete
|
||||
// before returning. Optionally filter by message id.
|
||||
// The destructor will not wait for outstanding calls, so if that
|
||||
// behavior is desired, call Flush() before destroying this object.
|
||||
void Flush(Thread* thread, uint32 id = MQID_ANY);
|
||||
|
||||
private:
|
||||
void InvokeHandler(Thread* thread, MessageHandler* handler, uint32 id);
|
||||
void RemoveHandler(MessageHandler* handler);
|
||||
|
||||
template <class ReturnT, class FunctorT, class HostT>
|
||||
void OnAsyncCallCompleted(
|
||||
AsyncFunctorMessageHandler<ReturnT, FunctorT>* handler,
|
||||
void (HostT::*callback)(ReturnT),
|
||||
HostT* callback_host) {
|
||||
AsyncInvoke<void>(handler->thread(),
|
||||
Bind(callback, callback_host, handler->result()));
|
||||
RemoveHandler(handler);
|
||||
}
|
||||
|
||||
template <class FunctorT, class HostT>
|
||||
void OnAsyncVoidCallCompleted(
|
||||
AsyncFunctorMessageHandler<void, FunctorT>* handler,
|
||||
void (HostT::*callback)(),
|
||||
HostT* callback_host) {
|
||||
AsyncInvoke<void>(handler->thread(), Bind(callback, callback_host));
|
||||
RemoveHandler(handler);
|
||||
}
|
||||
|
||||
CriticalSection crit_;
|
||||
ScopedPtrCollection<MessageHandler> handlers_;
|
||||
};
|
||||
|
||||
} // namespace talk_base
|
||||
|
||||
|
||||
#endif // TALK_BASE_ASYNCINVOKER_H_
|
207
talk/base/bind.h
207
talk/base/bind.h
@ -84,6 +84,18 @@ class MethodFunctor0 {
|
||||
ObjectT* object_;
|
||||
};
|
||||
|
||||
template <class FunctorT, class R>
|
||||
class Functor0 {
|
||||
public:
|
||||
explicit Functor0(const FunctorT& functor)
|
||||
: functor_(functor) {}
|
||||
R operator()() const {
|
||||
return functor_(); }
|
||||
private:
|
||||
FunctorT functor_;
|
||||
};
|
||||
|
||||
|
||||
#define FP_T(x) R (ObjectT::*x)()
|
||||
|
||||
template <class ObjectT, class R>
|
||||
@ -103,6 +115,16 @@ Bind(FP_T(method), const ObjectT* object) {
|
||||
method, object);
|
||||
}
|
||||
|
||||
#undef FP_T
|
||||
#define FP_T(x) R (*x)()
|
||||
|
||||
template <class R>
|
||||
Functor0<FP_T(NONAME), R>
|
||||
Bind(FP_T(function)) {
|
||||
return Functor0<FP_T(NONAME), R>(
|
||||
function);
|
||||
}
|
||||
|
||||
#undef FP_T
|
||||
|
||||
template <class ObjectT, class MethodT, class R,
|
||||
@ -121,6 +143,21 @@ class MethodFunctor1 {
|
||||
P1 p1_;
|
||||
};
|
||||
|
||||
template <class FunctorT, class R,
|
||||
class P1>
|
||||
class Functor1 {
|
||||
public:
|
||||
Functor1(const FunctorT& functor, P1 p1)
|
||||
: functor_(functor),
|
||||
p1_(p1) {}
|
||||
R operator()() const {
|
||||
return functor_(p1_); }
|
||||
private:
|
||||
FunctorT functor_;
|
||||
P1 p1_;
|
||||
};
|
||||
|
||||
|
||||
#define FP_T(x) R (ObjectT::*x)(P1)
|
||||
|
||||
template <class ObjectT, class R,
|
||||
@ -144,6 +181,18 @@ Bind(FP_T(method), const ObjectT* object,
|
||||
method, object, p1);
|
||||
}
|
||||
|
||||
#undef FP_T
|
||||
#define FP_T(x) R (*x)(P1)
|
||||
|
||||
template <class R,
|
||||
class P1>
|
||||
Functor1<FP_T(NONAME), R, P1>
|
||||
Bind(FP_T(function),
|
||||
typename detail::identity<P1>::type p1) {
|
||||
return Functor1<FP_T(NONAME), R, P1>(
|
||||
function, p1);
|
||||
}
|
||||
|
||||
#undef FP_T
|
||||
|
||||
template <class ObjectT, class MethodT, class R,
|
||||
@ -166,6 +215,24 @@ class MethodFunctor2 {
|
||||
P2 p2_;
|
||||
};
|
||||
|
||||
template <class FunctorT, class R,
|
||||
class P1,
|
||||
class P2>
|
||||
class Functor2 {
|
||||
public:
|
||||
Functor2(const FunctorT& functor, P1 p1, P2 p2)
|
||||
: functor_(functor),
|
||||
p1_(p1),
|
||||
p2_(p2) {}
|
||||
R operator()() const {
|
||||
return functor_(p1_, p2_); }
|
||||
private:
|
||||
FunctorT functor_;
|
||||
P1 p1_;
|
||||
P2 p2_;
|
||||
};
|
||||
|
||||
|
||||
#define FP_T(x) R (ObjectT::*x)(P1, P2)
|
||||
|
||||
template <class ObjectT, class R,
|
||||
@ -193,6 +260,20 @@ Bind(FP_T(method), const ObjectT* object,
|
||||
method, object, p1, p2);
|
||||
}
|
||||
|
||||
#undef FP_T
|
||||
#define FP_T(x) R (*x)(P1, P2)
|
||||
|
||||
template <class R,
|
||||
class P1,
|
||||
class P2>
|
||||
Functor2<FP_T(NONAME), R, P1, P2>
|
||||
Bind(FP_T(function),
|
||||
typename detail::identity<P1>::type p1,
|
||||
typename detail::identity<P2>::type p2) {
|
||||
return Functor2<FP_T(NONAME), R, P1, P2>(
|
||||
function, p1, p2);
|
||||
}
|
||||
|
||||
#undef FP_T
|
||||
|
||||
template <class ObjectT, class MethodT, class R,
|
||||
@ -219,6 +300,27 @@ class MethodFunctor3 {
|
||||
P3 p3_;
|
||||
};
|
||||
|
||||
template <class FunctorT, class R,
|
||||
class P1,
|
||||
class P2,
|
||||
class P3>
|
||||
class Functor3 {
|
||||
public:
|
||||
Functor3(const FunctorT& functor, P1 p1, P2 p2, P3 p3)
|
||||
: functor_(functor),
|
||||
p1_(p1),
|
||||
p2_(p2),
|
||||
p3_(p3) {}
|
||||
R operator()() const {
|
||||
return functor_(p1_, p2_, p3_); }
|
||||
private:
|
||||
FunctorT functor_;
|
||||
P1 p1_;
|
||||
P2 p2_;
|
||||
P3 p3_;
|
||||
};
|
||||
|
||||
|
||||
#define FP_T(x) R (ObjectT::*x)(P1, P2, P3)
|
||||
|
||||
template <class ObjectT, class R,
|
||||
@ -250,6 +352,22 @@ Bind(FP_T(method), const ObjectT* object,
|
||||
method, object, p1, p2, p3);
|
||||
}
|
||||
|
||||
#undef FP_T
|
||||
#define FP_T(x) R (*x)(P1, P2, P3)
|
||||
|
||||
template <class R,
|
||||
class P1,
|
||||
class P2,
|
||||
class P3>
|
||||
Functor3<FP_T(NONAME), R, P1, P2, P3>
|
||||
Bind(FP_T(function),
|
||||
typename detail::identity<P1>::type p1,
|
||||
typename detail::identity<P2>::type p2,
|
||||
typename detail::identity<P3>::type p3) {
|
||||
return Functor3<FP_T(NONAME), R, P1, P2, P3>(
|
||||
function, p1, p2, p3);
|
||||
}
|
||||
|
||||
#undef FP_T
|
||||
|
||||
template <class ObjectT, class MethodT, class R,
|
||||
@ -280,6 +398,30 @@ class MethodFunctor4 {
|
||||
P4 p4_;
|
||||
};
|
||||
|
||||
template <class FunctorT, class R,
|
||||
class P1,
|
||||
class P2,
|
||||
class P3,
|
||||
class P4>
|
||||
class Functor4 {
|
||||
public:
|
||||
Functor4(const FunctorT& functor, P1 p1, P2 p2, P3 p3, P4 p4)
|
||||
: functor_(functor),
|
||||
p1_(p1),
|
||||
p2_(p2),
|
||||
p3_(p3),
|
||||
p4_(p4) {}
|
||||
R operator()() const {
|
||||
return functor_(p1_, p2_, p3_, p4_); }
|
||||
private:
|
||||
FunctorT functor_;
|
||||
P1 p1_;
|
||||
P2 p2_;
|
||||
P3 p3_;
|
||||
P4 p4_;
|
||||
};
|
||||
|
||||
|
||||
#define FP_T(x) R (ObjectT::*x)(P1, P2, P3, P4)
|
||||
|
||||
template <class ObjectT, class R,
|
||||
@ -315,6 +457,24 @@ Bind(FP_T(method), const ObjectT* object,
|
||||
method, object, p1, p2, p3, p4);
|
||||
}
|
||||
|
||||
#undef FP_T
|
||||
#define FP_T(x) R (*x)(P1, P2, P3, P4)
|
||||
|
||||
template <class R,
|
||||
class P1,
|
||||
class P2,
|
||||
class P3,
|
||||
class P4>
|
||||
Functor4<FP_T(NONAME), R, P1, P2, P3, P4>
|
||||
Bind(FP_T(function),
|
||||
typename detail::identity<P1>::type p1,
|
||||
typename detail::identity<P2>::type p2,
|
||||
typename detail::identity<P3>::type p3,
|
||||
typename detail::identity<P4>::type p4) {
|
||||
return Functor4<FP_T(NONAME), R, P1, P2, P3, P4>(
|
||||
function, p1, p2, p3, p4);
|
||||
}
|
||||
|
||||
#undef FP_T
|
||||
|
||||
template <class ObjectT, class MethodT, class R,
|
||||
@ -349,6 +509,33 @@ class MethodFunctor5 {
|
||||
P5 p5_;
|
||||
};
|
||||
|
||||
template <class FunctorT, class R,
|
||||
class P1,
|
||||
class P2,
|
||||
class P3,
|
||||
class P4,
|
||||
class P5>
|
||||
class Functor5 {
|
||||
public:
|
||||
Functor5(const FunctorT& functor, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5)
|
||||
: functor_(functor),
|
||||
p1_(p1),
|
||||
p2_(p2),
|
||||
p3_(p3),
|
||||
p4_(p4),
|
||||
p5_(p5) {}
|
||||
R operator()() const {
|
||||
return functor_(p1_, p2_, p3_, p4_, p5_); }
|
||||
private:
|
||||
FunctorT functor_;
|
||||
P1 p1_;
|
||||
P2 p2_;
|
||||
P3 p3_;
|
||||
P4 p4_;
|
||||
P5 p5_;
|
||||
};
|
||||
|
||||
|
||||
#define FP_T(x) R (ObjectT::*x)(P1, P2, P3, P4, P5)
|
||||
|
||||
template <class ObjectT, class R,
|
||||
@ -388,6 +575,26 @@ Bind(FP_T(method), const ObjectT* object,
|
||||
method, object, p1, p2, p3, p4, p5);
|
||||
}
|
||||
|
||||
#undef FP_T
|
||||
#define FP_T(x) R (*x)(P1, P2, P3, P4, P5)
|
||||
|
||||
template <class R,
|
||||
class P1,
|
||||
class P2,
|
||||
class P3,
|
||||
class P4,
|
||||
class P5>
|
||||
Functor5<FP_T(NONAME), R, P1, P2, P3, P4, P5>
|
||||
Bind(FP_T(function),
|
||||
typename detail::identity<P1>::type p1,
|
||||
typename detail::identity<P2>::type p2,
|
||||
typename detail::identity<P3>::type p3,
|
||||
typename detail::identity<P4>::type p4,
|
||||
typename detail::identity<P5>::type p5) {
|
||||
return Functor5<FP_T(NONAME), R, P1, P2, P3, P4, P5>(
|
||||
function, p1, p2, p3, p4, p5);
|
||||
}
|
||||
|
||||
#undef FP_T
|
||||
|
||||
} // namespace talk_base
|
||||
|
@ -91,6 +91,24 @@ class MethodFunctor$i {
|
||||
|
||||
};
|
||||
|
||||
template <class FunctorT, class R$for j [[,
|
||||
class P$j]]>
|
||||
class Functor$i {
|
||||
public:
|
||||
$if i == 0 [[explicit ]]
|
||||
Functor$i(const FunctorT& functor$for j [[, P$j p$j]])
|
||||
: functor_(functor)$for j [[,
|
||||
p$(j)_(p$j)]] {}
|
||||
R operator()() const {
|
||||
return functor_($for j , [[p$(j)_]]); }
|
||||
private:
|
||||
FunctorT functor_;$for j [[
|
||||
|
||||
P$j p$(j)_;]]
|
||||
|
||||
};
|
||||
|
||||
|
||||
#define FP_T(x) R (ObjectT::*x)($for j , [[P$j]])
|
||||
|
||||
template <class ObjectT, class R$for j [[,
|
||||
@ -114,6 +132,18 @@ Bind(FP_T(method), const ObjectT* object$for j [[,
|
||||
method, object$for j [[, p$j]]);
|
||||
}
|
||||
|
||||
#undef FP_T
|
||||
#define FP_T(x) R (*x)($for j , [[P$j]])
|
||||
|
||||
template <class R$for j [[,
|
||||
class P$j]]>
|
||||
Functor$i<FP_T(NONAME), R$for j [[, P$j]]>
|
||||
Bind(FP_T(function)$for j [[,
|
||||
typename detail::identity<P$j>::type p$j]]) {
|
||||
return Functor$i<FP_T(NONAME), R$for j [[, P$j]]>(
|
||||
function$for j [[, p$j]]);
|
||||
}
|
||||
|
||||
#undef FP_T
|
||||
|
||||
]]
|
||||
|
@ -43,6 +43,10 @@ struct MethodBindTester {
|
||||
mutable int call_count;
|
||||
};
|
||||
|
||||
int Return42() { return 42; }
|
||||
int Negate(int a) { return -a; }
|
||||
int Multiply(int a, int b) { return a * b; }
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(BindTest, BindToMethod) {
|
||||
@ -71,4 +75,10 @@ TEST(BindTest, BindToMethod) {
|
||||
EXPECT_EQ(8, object.call_count);
|
||||
}
|
||||
|
||||
TEST(BindTest, BindToFunction) {
|
||||
EXPECT_EQ(42, Bind(&Return42)());
|
||||
EXPECT_EQ(3, Bind(&Negate, -3)());
|
||||
EXPECT_EQ(56, Bind(&Multiply, 8, 7)());
|
||||
}
|
||||
|
||||
} // namespace talk_base
|
||||
|
291
talk/base/callback.h
Normal file
291
talk/base/callback.h
Normal file
@ -0,0 +1,291 @@
|
||||
// This file was GENERATED by command:
|
||||
// pump.py callback.h.pump
|
||||
// DO NOT EDIT BY HAND!!!
|
||||
|
||||
/*
|
||||
* libjingle
|
||||
* Copyright 2012 Google Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
// To generate callback.h from callback.h.pump, execute:
|
||||
// /home/build/google3/third_party/gtest/scripts/pump.py callback.h.pump
|
||||
|
||||
// Callbacks are callable object containers. They can hold a function pointer
|
||||
// or a function object and behave like a value type. Internally, data is
|
||||
// reference-counted, making copies and pass-by-value inexpensive.
|
||||
//
|
||||
// Callbacks are typed using template arguments. The format is:
|
||||
// CallbackN<ReturnType, ParamType1, ..., ParamTypeN>
|
||||
// where N is the number of arguments supplied to the callable object.
|
||||
// Callbacks are invoked using operator(), just like a function or a function
|
||||
// object. Default-constructed callbacks are "empty," and executing an empty
|
||||
// callback does nothing. A callback can be made empty by assigning it from
|
||||
// a default-constructed callback.
|
||||
//
|
||||
// Callbacks are similar in purpose to std::function (which isn't available on
|
||||
// all platforms we support) and a lightweight alternative to sigslots. Since
|
||||
// they effectively hide the type of the object they call, they're useful in
|
||||
// breaking dependencies between objects that need to interact with one another.
|
||||
// Notably, they can hold the results of Bind(), std::bind*, etc, without
|
||||
// needing
|
||||
// to know the resulting object type of those calls.
|
||||
//
|
||||
// Sigslots, on the other hand, provide a fuller feature set, such as multiple
|
||||
// subscriptions to a signal, optional thread-safety, and lifetime tracking of
|
||||
// slots. When these features are needed, choose sigslots.
|
||||
//
|
||||
// Example:
|
||||
// int sqr(int x) { return x * x; }
|
||||
// struct AddK {
|
||||
// int k;
|
||||
// int operator()(int x) const { return x + k; }
|
||||
// } add_k = {5};
|
||||
//
|
||||
// Callback1<int, int> my_callback;
|
||||
// cout << my_callback.empty() << endl; // true
|
||||
//
|
||||
// my_callback = Callback1<int, int>(&sqr);
|
||||
// cout << my_callback.empty() << endl; // false
|
||||
// cout << my_callback(3) << endl; // 9
|
||||
//
|
||||
// my_callback = Callback1<int, int>(add_k);
|
||||
// cout << my_callback(10) << endl; // 15
|
||||
//
|
||||
// my_callback = Callback1<int, int>();
|
||||
// cout << my_callback.empty() << endl; // true
|
||||
|
||||
#ifndef TALK_BASE_CALLBACK_H_
|
||||
#define TALK_BASE_CALLBACK_H_
|
||||
|
||||
#include "talk/base/logging.h"
|
||||
#include "talk/base/refcount.h"
|
||||
#include "talk/base/scoped_ref_ptr.h"
|
||||
|
||||
namespace talk_base {
|
||||
|
||||
template <class R>
|
||||
class Callback0 {
|
||||
public:
|
||||
// Default copy operations are appropriate for this class.
|
||||
Callback0() {}
|
||||
template <class T> Callback0(const T& functor)
|
||||
: helper_(new RefCountedObject< HelperImpl<T> >(functor)) {}
|
||||
R operator()() {
|
||||
if (empty()) {
|
||||
LOG_F(LS_WARNING) << "Tried to execute an empty callback.";
|
||||
return R();
|
||||
}
|
||||
return helper_->Run();
|
||||
}
|
||||
bool empty() const { return !helper_; }
|
||||
|
||||
private:
|
||||
struct Helper : RefCountInterface {
|
||||
virtual ~Helper() {}
|
||||
virtual R Run() = 0;
|
||||
};
|
||||
template <class T> struct HelperImpl : Helper {
|
||||
explicit HelperImpl(const T& functor) : functor_(functor) {}
|
||||
virtual R Run() {
|
||||
return functor_();
|
||||
}
|
||||
T functor_;
|
||||
};
|
||||
scoped_refptr<Helper> helper_;
|
||||
};
|
||||
|
||||
template <class R,
|
||||
class P1>
|
||||
class Callback1 {
|
||||
public:
|
||||
// Default copy operations are appropriate for this class.
|
||||
Callback1() {}
|
||||
template <class T> Callback1(const T& functor)
|
||||
: helper_(new RefCountedObject< HelperImpl<T> >(functor)) {}
|
||||
R operator()(P1 p1) {
|
||||
if (empty()) {
|
||||
LOG_F(LS_WARNING) << "Tried to execute an empty callback.";
|
||||
return R();
|
||||
}
|
||||
return helper_->Run(p1);
|
||||
}
|
||||
bool empty() const { return !helper_; }
|
||||
|
||||
private:
|
||||
struct Helper : RefCountInterface {
|
||||
virtual ~Helper() {}
|
||||
virtual R Run(P1 p1) = 0;
|
||||
};
|
||||
template <class T> struct HelperImpl : Helper {
|
||||
explicit HelperImpl(const T& functor) : functor_(functor) {}
|
||||
virtual R Run(P1 p1) {
|
||||
return functor_(p1);
|
||||
}
|
||||
T functor_;
|
||||
};
|
||||
scoped_refptr<Helper> helper_;
|
||||
};
|
||||
|
||||
template <class R,
|
||||
class P1,
|
||||
class P2>
|
||||
class Callback2 {
|
||||
public:
|
||||
// Default copy operations are appropriate for this class.
|
||||
Callback2() {}
|
||||
template <class T> Callback2(const T& functor)
|
||||
: helper_(new RefCountedObject< HelperImpl<T> >(functor)) {}
|
||||
R operator()(P1 p1, P2 p2) {
|
||||
if (empty()) {
|
||||
LOG_F(LS_WARNING) << "Tried to execute an empty callback.";
|
||||
return R();
|
||||
}
|
||||
return helper_->Run(p1, p2);
|
||||
}
|
||||
bool empty() const { return !helper_; }
|
||||
|
||||
private:
|
||||
struct Helper : RefCountInterface {
|
||||
virtual ~Helper() {}
|
||||
virtual R Run(P1 p1, P2 p2) = 0;
|
||||
};
|
||||
template <class T> struct HelperImpl : Helper {
|
||||
explicit HelperImpl(const T& functor) : functor_(functor) {}
|
||||
virtual R Run(P1 p1, P2 p2) {
|
||||
return functor_(p1, p2);
|
||||
}
|
||||
T functor_;
|
||||
};
|
||||
scoped_refptr<Helper> helper_;
|
||||
};
|
||||
|
||||
template <class R,
|
||||
class P1,
|
||||
class P2,
|
||||
class P3>
|
||||
class Callback3 {
|
||||
public:
|
||||
// Default copy operations are appropriate for this class.
|
||||
Callback3() {}
|
||||
template <class T> Callback3(const T& functor)
|
||||
: helper_(new RefCountedObject< HelperImpl<T> >(functor)) {}
|
||||
R operator()(P1 p1, P2 p2, P3 p3) {
|
||||
if (empty()) {
|
||||
LOG_F(LS_WARNING) << "Tried to execute an empty callback.";
|
||||
return R();
|
||||
}
|
||||
return helper_->Run(p1, p2, p3);
|
||||
}
|
||||
bool empty() const { return !helper_; }
|
||||
|
||||
private:
|
||||
struct Helper : RefCountInterface {
|
||||
virtual ~Helper() {}
|
||||
virtual R Run(P1 p1, P2 p2, P3 p3) = 0;
|
||||
};
|
||||
template <class T> struct HelperImpl : Helper {
|
||||
explicit HelperImpl(const T& functor) : functor_(functor) {}
|
||||
virtual R Run(P1 p1, P2 p2, P3 p3) {
|
||||
return functor_(p1, p2, p3);
|
||||
}
|
||||
T functor_;
|
||||
};
|
||||
scoped_refptr<Helper> helper_;
|
||||
};
|
||||
|
||||
template <class R,
|
||||
class P1,
|
||||
class P2,
|
||||
class P3,
|
||||
class P4>
|
||||
class Callback4 {
|
||||
public:
|
||||
// Default copy operations are appropriate for this class.
|
||||
Callback4() {}
|
||||
template <class T> Callback4(const T& functor)
|
||||
: helper_(new RefCountedObject< HelperImpl<T> >(functor)) {}
|
||||
R operator()(P1 p1, P2 p2, P3 p3, P4 p4) {
|
||||
if (empty()) {
|
||||
LOG_F(LS_WARNING) << "Tried to execute an empty callback.";
|
||||
return R();
|
||||
}
|
||||
return helper_->Run(p1, p2, p3, p4);
|
||||
}
|
||||
bool empty() const { return !helper_; }
|
||||
|
||||
private:
|
||||
struct Helper : RefCountInterface {
|
||||
virtual ~Helper() {}
|
||||
virtual R Run(P1 p1, P2 p2, P3 p3, P4 p4) = 0;
|
||||
};
|
||||
template <class T> struct HelperImpl : Helper {
|
||||
explicit HelperImpl(const T& functor) : functor_(functor) {}
|
||||
virtual R Run(P1 p1, P2 p2, P3 p3, P4 p4) {
|
||||
return functor_(p1, p2, p3, p4);
|
||||
}
|
||||
T functor_;
|
||||
};
|
||||
scoped_refptr<Helper> helper_;
|
||||
};
|
||||
|
||||
template <class R,
|
||||
class P1,
|
||||
class P2,
|
||||
class P3,
|
||||
class P4,
|
||||
class P5>
|
||||
class Callback5 {
|
||||
public:
|
||||
// Default copy operations are appropriate for this class.
|
||||
Callback5() {}
|
||||
template <class T> Callback5(const T& functor)
|
||||
: helper_(new RefCountedObject< HelperImpl<T> >(functor)) {}
|
||||
R operator()(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) {
|
||||
if (empty()) {
|
||||
LOG_F(LS_WARNING) << "Tried to execute an empty callback.";
|
||||
return R();
|
||||
}
|
||||
return helper_->Run(p1, p2, p3, p4, p5);
|
||||
}
|
||||
bool empty() const { return !helper_; }
|
||||
|
||||
private:
|
||||
struct Helper : RefCountInterface {
|
||||
virtual ~Helper() {}
|
||||
virtual R Run(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) = 0;
|
||||
};
|
||||
template <class T> struct HelperImpl : Helper {
|
||||
explicit HelperImpl(const T& functor) : functor_(functor) {}
|
||||
virtual R Run(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) {
|
||||
return functor_(p1, p2, p3, p4, p5);
|
||||
}
|
||||
T functor_;
|
||||
};
|
||||
scoped_refptr<Helper> helper_;
|
||||
};
|
||||
} // namespace talk_base
|
||||
|
||||
|
||||
#endif // TALK_BASE_CALLBACK_H_
|
123
talk/base/callback.h.pump
Normal file
123
talk/base/callback.h.pump
Normal file
@ -0,0 +1,123 @@
|
||||
/*
|
||||
* libjingle
|
||||
* Copyright 2012 Google Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
// To generate callback.h from callback.h.pump, execute:
|
||||
// /home/build/google3/third_party/gtest/scripts/pump.py callback.h.pump
|
||||
|
||||
// Callbacks are callable object containers. They can hold a function pointer
|
||||
// or a function object and behave like a value type. Internally, data is
|
||||
// reference-counted, making copies and pass-by-value inexpensive.
|
||||
//
|
||||
// Callbacks are typed using template arguments. The format is:
|
||||
// CallbackN<ReturnType, ParamType1, ..., ParamTypeN>
|
||||
// where N is the number of arguments supplied to the callable object.
|
||||
// Callbacks are invoked using operator(), just like a function or a function
|
||||
// object. Default-constructed callbacks are "empty," and executing an empty
|
||||
// callback does nothing. A callback can be made empty by assigning it from
|
||||
// a default-constructed callback.
|
||||
//
|
||||
// Callbacks are similar in purpose to std::function (which isn't available on
|
||||
// all platforms we support) and a lightweight alternative to sigslots. Since
|
||||
// they effectively hide the type of the object they call, they're useful in
|
||||
// breaking dependencies between objects that need to interact with one another.
|
||||
// Notably, they can hold the results of Bind(), std::bind*, etc, without needing
|
||||
// to know the resulting object type of those calls.
|
||||
//
|
||||
// Sigslots, on the other hand, provide a fuller feature set, such as multiple
|
||||
// subscriptions to a signal, optional thread-safety, and lifetime tracking of
|
||||
// slots. When these features are needed, choose sigslots.
|
||||
//
|
||||
// Example:
|
||||
// int sqr(int x) { return x * x; }
|
||||
// struct AddK {
|
||||
// int k;
|
||||
// int operator()(int x) const { return x + k; }
|
||||
// } add_k = {5};
|
||||
//
|
||||
// Callback1<int, int> my_callback;
|
||||
// cout << my_callback.empty() << endl; // true
|
||||
//
|
||||
// my_callback = Callback1<int, int>(&sqr);
|
||||
// cout << my_callback.empty() << endl; // false
|
||||
// cout << my_callback(3) << endl; // 9
|
||||
//
|
||||
// my_callback = Callback1<int, int>(add_k);
|
||||
// cout << my_callback(10) << endl; // 15
|
||||
//
|
||||
// my_callback = Callback1<int, int>();
|
||||
// cout << my_callback.empty() << endl; // true
|
||||
|
||||
#ifndef TALK_BASE_CALLBACK_H_
|
||||
#define TALK_BASE_CALLBACK_H_
|
||||
|
||||
#include "talk/base/logging.h"
|
||||
#include "talk/base/refcount.h"
|
||||
#include "talk/base/scoped_ref_ptr.h"
|
||||
|
||||
namespace talk_base {
|
||||
|
||||
$var n = 5
|
||||
$range i 0..n
|
||||
$for i [[
|
||||
$range j 1..i
|
||||
|
||||
template <class R$for j [[,
|
||||
class P$j]]>
|
||||
class Callback$i {
|
||||
public:
|
||||
// Default copy operations are appropriate for this class.
|
||||
Callback$i() {}
|
||||
template <class T> Callback$i(const T& functor)
|
||||
: helper_(new RefCountedObject< HelperImpl<T> >(functor)) {}
|
||||
R operator()($for j , [[P$j p$j]]) {
|
||||
if (empty()) {
|
||||
LOG_F(LS_WARNING) << "Tried to execute an empty callback.";
|
||||
return R();
|
||||
}
|
||||
return helper_->Run($for j , [[p$j]]);
|
||||
}
|
||||
bool empty() const { return !helper_; }
|
||||
|
||||
private:
|
||||
struct Helper : RefCountInterface {
|
||||
virtual ~Helper() {}
|
||||
virtual R Run($for j , [[P$j p$j]]) = 0;
|
||||
};
|
||||
template <class T> struct HelperImpl : Helper {
|
||||
explicit HelperImpl(const T& functor) : functor_(functor) {}
|
||||
virtual R Run($for j , [[P$j p$j]]) {
|
||||
return functor_($for j , [[p$j]]);
|
||||
}
|
||||
T functor_;
|
||||
};
|
||||
scoped_refptr<Helper> helper_;
|
||||
};
|
||||
|
||||
]]
|
||||
} // namespace talk_base
|
||||
|
||||
#endif // TALK_BASE_CALLBACK_H_
|
98
talk/base/callback_unittest.cc
Normal file
98
talk/base/callback_unittest.cc
Normal file
@ -0,0 +1,98 @@
|
||||
/*
|
||||
* libjingle
|
||||
* Copyright 2004--2011, Google Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "talk/base/bind.h"
|
||||
#include "talk/base/callback.h"
|
||||
#include "talk/base/gunit.h"
|
||||
|
||||
namespace talk_base {
|
||||
|
||||
namespace {
|
||||
|
||||
void f() {}
|
||||
int g() { return 42; }
|
||||
int h(int x) { return x * x; }
|
||||
void i(int& x) { x *= x; } // NOLINT: Testing refs
|
||||
|
||||
struct BindTester {
|
||||
int a() { return 24; }
|
||||
int b(int x) const { return x * x; }
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(CallbackTest, VoidReturn) {
|
||||
Callback0<void> cb;
|
||||
EXPECT_TRUE(cb.empty());
|
||||
cb(); // Executing an empty callback should not crash.
|
||||
cb = Callback0<void>(&f);
|
||||
EXPECT_FALSE(cb.empty());
|
||||
cb();
|
||||
}
|
||||
|
||||
TEST(CallbackTest, IntReturn) {
|
||||
Callback0<int> cb;
|
||||
EXPECT_TRUE(cb.empty());
|
||||
cb = Callback0<int>(&g);
|
||||
EXPECT_FALSE(cb.empty());
|
||||
EXPECT_EQ(42, cb());
|
||||
EXPECT_EQ(42, cb());
|
||||
}
|
||||
|
||||
TEST(CallbackTest, OneParam) {
|
||||
Callback1<int, int> cb1(&h);
|
||||
EXPECT_FALSE(cb1.empty());
|
||||
EXPECT_EQ(9, cb1(-3));
|
||||
EXPECT_EQ(100, cb1(10));
|
||||
|
||||
// Try clearing a callback.
|
||||
cb1 = Callback1<int, int>();
|
||||
EXPECT_TRUE(cb1.empty());
|
||||
|
||||
// Try a callback with a ref parameter.
|
||||
Callback1<void, int&> cb2(&i);
|
||||
int x = 3;
|
||||
cb2(x);
|
||||
EXPECT_EQ(9, x);
|
||||
cb2(x);
|
||||
EXPECT_EQ(81, x);
|
||||
}
|
||||
|
||||
TEST(CallbackTest, WithBind) {
|
||||
BindTester t;
|
||||
Callback0<int> cb1 = Bind(&BindTester::a, &t);
|
||||
EXPECT_EQ(24, cb1());
|
||||
EXPECT_EQ(24, cb1());
|
||||
cb1 = Bind(&BindTester::b, &t, 10);
|
||||
EXPECT_EQ(100, cb1());
|
||||
EXPECT_EQ(100, cb1());
|
||||
cb1 = Bind(&BindTester::b, &t, 5);
|
||||
EXPECT_EQ(25, cb1());
|
||||
EXPECT_EQ(25, cb1());
|
||||
}
|
||||
|
||||
} // namespace talk_base
|
@ -28,6 +28,7 @@
|
||||
#ifndef TALK_BASE_MESSAGEHANDLER_H_
|
||||
#define TALK_BASE_MESSAGEHANDLER_H_
|
||||
|
||||
#include "talk/base/callback.h"
|
||||
#include "talk/base/constructormagic.h"
|
||||
|
||||
namespace talk_base {
|
||||
@ -38,16 +39,52 @@ struct Message;
|
||||
|
||||
class MessageHandler {
|
||||
public:
|
||||
virtual ~MessageHandler();
|
||||
virtual void OnMessage(Message* msg) = 0;
|
||||
|
||||
protected:
|
||||
MessageHandler() {}
|
||||
virtual ~MessageHandler();
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(MessageHandler);
|
||||
};
|
||||
|
||||
// Helper class to facilitate executing a functor on a thread.
|
||||
template <class ReturnT, class FunctorT>
|
||||
class FunctorMessageHandler : public MessageHandler {
|
||||
public:
|
||||
explicit FunctorMessageHandler(const FunctorT& functor)
|
||||
: functor_(functor) {}
|
||||
virtual void OnMessage(Message* msg) {
|
||||
result_ = functor_();
|
||||
if (!callback_.empty()) callback_();
|
||||
}
|
||||
const ReturnT& result() const { return result_; }
|
||||
void SetCallback(const Callback0<void>& callback) { callback_ = callback; }
|
||||
private:
|
||||
FunctorT functor_;
|
||||
ReturnT result_;
|
||||
Callback0<void> callback_;
|
||||
};
|
||||
|
||||
// Specialization for ReturnT of void.
|
||||
template <class FunctorT>
|
||||
class FunctorMessageHandler<void, FunctorT> : public MessageHandler {
|
||||
public:
|
||||
explicit FunctorMessageHandler(const FunctorT& functor)
|
||||
: functor_(functor) {}
|
||||
virtual void OnMessage(Message* msg) {
|
||||
functor_();
|
||||
if (!callback_.empty()) callback_();
|
||||
}
|
||||
void result() const {}
|
||||
void SetCallback(const Callback0<void>& callback) { callback_ = callback; }
|
||||
private:
|
||||
FunctorT functor_;
|
||||
Callback0<void> callback_;
|
||||
};
|
||||
|
||||
|
||||
} // namespace talk_base
|
||||
|
||||
#endif // TALK_BASE_MESSAGEHANDLER_H_
|
||||
|
77
talk/base/scopedptrcollection.h
Normal file
77
talk/base/scopedptrcollection.h
Normal file
@ -0,0 +1,77 @@
|
||||
/*
|
||||
* libjingle
|
||||
* Copyright 2014 Google Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
// Stores a collection of pointers that are deleted when the container is
|
||||
// destructed.
|
||||
|
||||
#ifndef TALK_BASE_SCOPEDPTRCOLLECTION_H_
|
||||
#define TALK_BASE_SCOPEDPTRCOLLECTION_H_
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
#include "talk/base/basictypes.h"
|
||||
#include "talk/base/constructormagic.h"
|
||||
|
||||
namespace talk_base {
|
||||
|
||||
template<class T>
|
||||
class ScopedPtrCollection {
|
||||
public:
|
||||
typedef std::vector<T*> VectorT;
|
||||
|
||||
ScopedPtrCollection() { }
|
||||
~ScopedPtrCollection() {
|
||||
for (typename VectorT::iterator it = collection_.begin();
|
||||
it != collection_.end(); ++it) {
|
||||
delete *it;
|
||||
}
|
||||
}
|
||||
|
||||
const VectorT& collection() const { return collection_; }
|
||||
void Reserve(size_t size) {
|
||||
collection_.reserve(size);
|
||||
}
|
||||
void PushBack(T* t) {
|
||||
collection_.push_back(t);
|
||||
}
|
||||
|
||||
// Remove |t| from the collection without deleting it.
|
||||
void Remove(T* t) {
|
||||
collection_.erase(std::remove(collection_.begin(), collection_.end(), t),
|
||||
collection_.end());
|
||||
}
|
||||
|
||||
private:
|
||||
VectorT collection_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ScopedPtrCollection);
|
||||
};
|
||||
|
||||
} // namespace talk_base
|
||||
|
||||
#endif // TALK_BASE_SCOPEDPTRCOLLECTION_H_
|
90
talk/base/scopedptrcollection_unittest.cc
Normal file
90
talk/base/scopedptrcollection_unittest.cc
Normal file
@ -0,0 +1,90 @@
|
||||
/*
|
||||
* libjingle
|
||||
* Copyright 2014 Google Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "talk/base/scopedptrcollection.h"
|
||||
#include "talk/base/gunit.h"
|
||||
|
||||
namespace talk_base {
|
||||
|
||||
namespace {
|
||||
|
||||
class InstanceCounter {
|
||||
public:
|
||||
explicit InstanceCounter(int* num_instances)
|
||||
: num_instances_(num_instances) {
|
||||
++(*num_instances_);
|
||||
}
|
||||
~InstanceCounter() {
|
||||
--(*num_instances_);
|
||||
}
|
||||
|
||||
private:
|
||||
int* num_instances_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(InstanceCounter);
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
class ScopedPtrCollectionTest : public testing::Test {
|
||||
protected:
|
||||
ScopedPtrCollectionTest()
|
||||
: num_instances_(0),
|
||||
collection_(new ScopedPtrCollection<InstanceCounter>()) {
|
||||
}
|
||||
|
||||
int num_instances_;
|
||||
scoped_ptr<ScopedPtrCollection<InstanceCounter> > collection_;
|
||||
};
|
||||
|
||||
TEST_F(ScopedPtrCollectionTest, PushBack) {
|
||||
EXPECT_EQ(0u, collection_->collection().size());
|
||||
EXPECT_EQ(0, num_instances_);
|
||||
const int kNum = 100;
|
||||
for (int i = 0; i < kNum; ++i) {
|
||||
collection_->PushBack(new InstanceCounter(&num_instances_));
|
||||
}
|
||||
EXPECT_EQ(static_cast<size_t>(kNum), collection_->collection().size());
|
||||
EXPECT_EQ(kNum, num_instances_);
|
||||
collection_.reset();
|
||||
EXPECT_EQ(0, num_instances_);
|
||||
}
|
||||
|
||||
TEST_F(ScopedPtrCollectionTest, Remove) {
|
||||
InstanceCounter* ic = new InstanceCounter(&num_instances_);
|
||||
collection_->PushBack(ic);
|
||||
EXPECT_EQ(1u, collection_->collection().size());
|
||||
collection_->Remove(ic);
|
||||
EXPECT_EQ(1, num_instances_);
|
||||
collection_.reset();
|
||||
EXPECT_EQ(1, num_instances_);
|
||||
delete ic;
|
||||
EXPECT_EQ(0, num_instances_);
|
||||
}
|
||||
|
||||
|
||||
} // namespace talk_base
|
@ -223,33 +223,6 @@ class Thread : public MessageQueue {
|
||||
void Join();
|
||||
|
||||
private:
|
||||
// Helper class to facilitate executing a functor on a thread.
|
||||
template <class ReturnT, class FunctorT>
|
||||
class FunctorMessageHandler : public MessageHandler {
|
||||
public:
|
||||
explicit FunctorMessageHandler(const FunctorT& functor)
|
||||
: functor_(functor) {}
|
||||
virtual void OnMessage(Message* msg) {
|
||||
result_ = functor_();
|
||||
}
|
||||
const ReturnT& result() const { return result_; }
|
||||
private:
|
||||
FunctorT functor_;
|
||||
ReturnT result_;
|
||||
};
|
||||
|
||||
// Specialization for ReturnT of void.
|
||||
template <class FunctorT>
|
||||
class FunctorMessageHandler<void, FunctorT> : public MessageHandler {
|
||||
public:
|
||||
explicit FunctorMessageHandler(const FunctorT& functor)
|
||||
: functor_(functor) {}
|
||||
virtual void OnMessage(Message* msg) { functor_(); }
|
||||
void result() const {}
|
||||
private:
|
||||
FunctorT functor_;
|
||||
};
|
||||
|
||||
static void *PreRun(void *pv);
|
||||
|
||||
// ThreadManager calls this instead WrapCurrent() because
|
||||
|
@ -25,6 +25,7 @@
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "talk/base/asyncinvoker.h"
|
||||
#include "talk/base/asyncudpsocket.h"
|
||||
#include "talk/base/event.h"
|
||||
#include "talk/base/gunit.h"
|
||||
@ -150,16 +151,22 @@ class SignalWhenDestroyedThread : public Thread {
|
||||
};
|
||||
|
||||
// Function objects to test Thread::Invoke.
|
||||
struct Functor1 {
|
||||
struct FunctorA {
|
||||
int operator()() { return 42; }
|
||||
};
|
||||
class Functor2 {
|
||||
class FunctorB {
|
||||
public:
|
||||
explicit Functor2(bool* flag) : flag_(flag) {}
|
||||
explicit FunctorB(bool* flag) : flag_(flag) {}
|
||||
void operator()() { if (flag_) *flag_ = true; }
|
||||
private:
|
||||
bool* flag_;
|
||||
};
|
||||
struct FunctorC {
|
||||
int operator()() {
|
||||
Thread::Current()->ProcessMessages(50);
|
||||
return 24;
|
||||
}
|
||||
};
|
||||
|
||||
// See: https://code.google.com/p/webrtc/issues/detail?id=2409
|
||||
TEST(ThreadTest, DISABLED_Main) {
|
||||
@ -289,9 +296,9 @@ TEST(ThreadTest, Invoke) {
|
||||
Thread thread;
|
||||
thread.Start();
|
||||
// Try calling functors.
|
||||
EXPECT_EQ(42, thread.Invoke<int>(Functor1()));
|
||||
EXPECT_EQ(42, thread.Invoke<int>(FunctorA()));
|
||||
bool called = false;
|
||||
Functor2 f2(&called);
|
||||
FunctorB f2(&called);
|
||||
thread.Invoke<void>(f2);
|
||||
EXPECT_TRUE(called);
|
||||
// Try calling bare functions.
|
||||
@ -303,6 +310,152 @@ TEST(ThreadTest, Invoke) {
|
||||
thread.Invoke<void>(&LocalFuncs::Func2);
|
||||
}
|
||||
|
||||
class AsyncInvokeTest : public testing::Test {
|
||||
public:
|
||||
void IntCallback(int value) {
|
||||
EXPECT_EQ(expected_thread_, Thread::Current());
|
||||
int_value_ = value;
|
||||
}
|
||||
void AsyncInvokeIntCallback(AsyncInvoker* invoker, Thread* thread) {
|
||||
expected_thread_ = thread;
|
||||
invoker->AsyncInvoke(thread, FunctorC(),
|
||||
&AsyncInvokeTest::IntCallback,
|
||||
static_cast<AsyncInvokeTest*>(this));
|
||||
invoke_started_.Set();
|
||||
}
|
||||
void SetExpectedThreadForIntCallback(Thread* thread) {
|
||||
expected_thread_ = thread;
|
||||
}
|
||||
|
||||
protected:
|
||||
enum { kWaitTimeout = 1000 };
|
||||
AsyncInvokeTest()
|
||||
: int_value_(0),
|
||||
invoke_started_(true, false),
|
||||
expected_thread_(NULL) {}
|
||||
|
||||
int int_value_;
|
||||
Event invoke_started_;
|
||||
Thread* expected_thread_;
|
||||
};
|
||||
|
||||
TEST_F(AsyncInvokeTest, FireAndForget) {
|
||||
AsyncInvoker invoker;
|
||||
// Create and start the thread.
|
||||
Thread thread;
|
||||
thread.Start();
|
||||
// Try calling functor.
|
||||
bool called = false;
|
||||
invoker.AsyncInvoke<void>(&thread, FunctorB(&called));
|
||||
EXPECT_TRUE_WAIT(called, kWaitTimeout);
|
||||
}
|
||||
|
||||
TEST_F(AsyncInvokeTest, WithCallback) {
|
||||
AsyncInvoker invoker;
|
||||
// Create and start the thread.
|
||||
Thread thread;
|
||||
thread.Start();
|
||||
// Try calling functor.
|
||||
SetExpectedThreadForIntCallback(Thread::Current());
|
||||
invoker.AsyncInvoke(&thread, FunctorA(),
|
||||
&AsyncInvokeTest::IntCallback,
|
||||
static_cast<AsyncInvokeTest*>(this));
|
||||
EXPECT_EQ_WAIT(42, int_value_, kWaitTimeout);
|
||||
}
|
||||
|
||||
TEST_F(AsyncInvokeTest, CancelInvoker) {
|
||||
// Create and start the thread.
|
||||
Thread thread;
|
||||
thread.Start();
|
||||
// Try destroying invoker during call.
|
||||
{
|
||||
AsyncInvoker invoker;
|
||||
invoker.AsyncInvoke(&thread, FunctorC(),
|
||||
&AsyncInvokeTest::IntCallback,
|
||||
static_cast<AsyncInvokeTest*>(this));
|
||||
}
|
||||
// With invoker gone, callback should be cancelled.
|
||||
Thread::Current()->ProcessMessages(kWaitTimeout);
|
||||
EXPECT_EQ(0, int_value_);
|
||||
}
|
||||
|
||||
TEST_F(AsyncInvokeTest, CancelCallingThread) {
|
||||
AsyncInvoker invoker;
|
||||
{ // Create and start the thread.
|
||||
Thread thread;
|
||||
thread.Start();
|
||||
// Try calling functor.
|
||||
thread.Invoke<void>(Bind(&AsyncInvokeTest::AsyncInvokeIntCallback,
|
||||
static_cast<AsyncInvokeTest*>(this),
|
||||
&invoker, Thread::Current()));
|
||||
// Wait for the call to begin.
|
||||
ASSERT_TRUE(invoke_started_.Wait(kWaitTimeout));
|
||||
}
|
||||
// Calling thread is gone. Return message shouldn't happen.
|
||||
Thread::Current()->ProcessMessages(kWaitTimeout);
|
||||
EXPECT_EQ(0, int_value_);
|
||||
}
|
||||
|
||||
TEST_F(AsyncInvokeTest, KillInvokerBeforeExecute) {
|
||||
Thread thread;
|
||||
thread.Start();
|
||||
{
|
||||
AsyncInvoker invoker;
|
||||
// Try calling functor.
|
||||
thread.Invoke<void>(Bind(&AsyncInvokeTest::AsyncInvokeIntCallback,
|
||||
static_cast<AsyncInvokeTest*>(this),
|
||||
&invoker, Thread::Current()));
|
||||
// Wait for the call to begin.
|
||||
ASSERT_TRUE(invoke_started_.Wait(kWaitTimeout));
|
||||
}
|
||||
// Invoker is destroyed. Function should not execute.
|
||||
Thread::Current()->ProcessMessages(kWaitTimeout);
|
||||
EXPECT_EQ(0, int_value_);
|
||||
}
|
||||
|
||||
TEST_F(AsyncInvokeTest, Flush) {
|
||||
AsyncInvoker invoker;
|
||||
bool flag1 = false;
|
||||
bool flag2 = false;
|
||||
// Queue two async calls to the current thread.
|
||||
invoker.AsyncInvoke<void>(Thread::Current(),
|
||||
FunctorB(&flag1));
|
||||
invoker.AsyncInvoke<void>(Thread::Current(),
|
||||
FunctorB(&flag2));
|
||||
// Because we haven't pumped messages, these should not have run yet.
|
||||
EXPECT_FALSE(flag1);
|
||||
EXPECT_FALSE(flag2);
|
||||
// Force them to run now.
|
||||
invoker.Flush(Thread::Current());
|
||||
EXPECT_TRUE(flag1);
|
||||
EXPECT_TRUE(flag2);
|
||||
}
|
||||
|
||||
TEST_F(AsyncInvokeTest, FlushWithIds) {
|
||||
AsyncInvoker invoker;
|
||||
bool flag1 = false;
|
||||
bool flag2 = false;
|
||||
// Queue two async calls to the current thread, one with a message id.
|
||||
invoker.AsyncInvoke<void>(Thread::Current(),
|
||||
FunctorB(&flag1),
|
||||
5);
|
||||
invoker.AsyncInvoke<void>(Thread::Current(),
|
||||
FunctorB(&flag2));
|
||||
// Because we haven't pumped messages, these should not have run yet.
|
||||
EXPECT_FALSE(flag1);
|
||||
EXPECT_FALSE(flag2);
|
||||
// Execute pending calls with id == 5.
|
||||
invoker.Flush(Thread::Current(), 5);
|
||||
EXPECT_TRUE(flag1);
|
||||
EXPECT_FALSE(flag2);
|
||||
flag1 = false;
|
||||
// Execute all pending calls. The id == 5 call should not execute again.
|
||||
invoker.Flush(Thread::Current());
|
||||
EXPECT_FALSE(flag1);
|
||||
EXPECT_TRUE(flag2);
|
||||
}
|
||||
|
||||
|
||||
#ifdef WIN32
|
||||
class ComThreadTest : public testing::Test, public MessageHandler {
|
||||
public:
|
||||
|
@ -260,6 +260,8 @@
|
||||
'base/asyncfile.h',
|
||||
'base/asynchttprequest.cc',
|
||||
'base/asynchttprequest.h',
|
||||
'base/asyncinvoker.cc',
|
||||
'base/asyncinvoker.h',
|
||||
'base/asyncpacketsocket.h',
|
||||
'base/asyncresolverinterface.h',
|
||||
'base/asyncsocket.cc',
|
||||
@ -282,6 +284,7 @@
|
||||
'base/bytebuffer.cc',
|
||||
'base/bytebuffer.h',
|
||||
'base/byteorder.h',
|
||||
'base/callback.h',
|
||||
'base/checks.cc',
|
||||
'base/checks.h',
|
||||
'base/common.cc',
|
||||
@ -383,6 +386,7 @@
|
||||
'base/scoped_autorelease_pool.h',
|
||||
'base/scoped_ptr.h',
|
||||
'base/scoped_ref_ptr.h',
|
||||
'base/scopedptrcollection.h',
|
||||
'base/sec_buffer.h',
|
||||
'base/sha1.cc',
|
||||
'base/sha1.h',
|
||||
|
@ -154,6 +154,7 @@ talk.Library(env, name = "jingle",
|
||||
srcs = [
|
||||
"base/asyncfile.cc",
|
||||
"base/asynchttprequest.cc",
|
||||
"base/asyncinvoker.cc",
|
||||
"base/asyncsocket.cc",
|
||||
"base/asynctcpsocket.cc",
|
||||
"base/asyncudpsocket.cc",
|
||||
@ -540,6 +541,7 @@ talk.Unittest(env, name = "base",
|
||||
"base/buffer_unittest.cc",
|
||||
"base/bytebuffer_unittest.cc",
|
||||
"base/byteorder_unittest.cc",
|
||||
"base/callback_unittest.cc",
|
||||
"base/cpumonitor_unittest.cc",
|
||||
"base/crc32_unittest.cc",
|
||||
"base/event_unittest.cc",
|
||||
@ -569,6 +571,7 @@ talk.Unittest(env, name = "base",
|
||||
"base/ratetracker_unittest.cc",
|
||||
"base/referencecountedsingletonfactory_unittest.cc",
|
||||
"base/rollingaccumulator_unittest.cc",
|
||||
"base/scopedptrcollection_unittest.cc",
|
||||
"base/sha1digest_unittest.cc",
|
||||
"base/sharedexclusivelock_unittest.cc",
|
||||
"base/signalthread_unittest.cc",
|
||||
|
@ -120,6 +120,7 @@
|
||||
'base/buffer_unittest.cc',
|
||||
'base/bytebuffer_unittest.cc',
|
||||
'base/byteorder_unittest.cc',
|
||||
'base/callback_unittest.cc',
|
||||
'base/cpumonitor_unittest.cc',
|
||||
'base/crc32_unittest.cc',
|
||||
'base/event_unittest.cc',
|
||||
@ -148,6 +149,7 @@
|
||||
'base/ratetracker_unittest.cc',
|
||||
'base/referencecountedsingletonfactory_unittest.cc',
|
||||
'base/rollingaccumulator_unittest.cc',
|
||||
'base/scopedptrcollection_unittest.cc',
|
||||
'base/sha1digest_unittest.cc',
|
||||
'base/sharedexclusivelock_unittest.cc',
|
||||
'base/signalthread_unittest.cc',
|
||||
|
@ -168,6 +168,7 @@ struct AudioOptions {
|
||||
adjust_agc_delta.SetFrom(change.adjust_agc_delta);
|
||||
experimental_agc.SetFrom(change.experimental_agc);
|
||||
experimental_aec.SetFrom(change.experimental_aec);
|
||||
experimental_ns.SetFrom(change.experimental_ns);
|
||||
aec_dump.SetFrom(change.aec_dump);
|
||||
experimental_acm.SetFrom(change.experimental_acm);
|
||||
tx_agc_target_dbov.SetFrom(change.tx_agc_target_dbov);
|
||||
@ -195,6 +196,7 @@ struct AudioOptions {
|
||||
conference_mode == o.conference_mode &&
|
||||
experimental_agc == o.experimental_agc &&
|
||||
experimental_aec == o.experimental_aec &&
|
||||
experimental_ns == o.experimental_ns &&
|
||||
adjust_agc_delta == o.adjust_agc_delta &&
|
||||
aec_dump == o.aec_dump &&
|
||||
experimental_acm == o.experimental_acm &&
|
||||
@ -224,6 +226,7 @@ struct AudioOptions {
|
||||
ost << ToStringIfSet("agc_delta", adjust_agc_delta);
|
||||
ost << ToStringIfSet("experimental_agc", experimental_agc);
|
||||
ost << ToStringIfSet("experimental_aec", experimental_aec);
|
||||
ost << ToStringIfSet("experimental_ns", experimental_ns);
|
||||
ost << ToStringIfSet("aec_dump", aec_dump);
|
||||
ost << ToStringIfSet("experimental_acm", experimental_acm);
|
||||
ost << ToStringIfSet("tx_agc_target_dbov", tx_agc_target_dbov);
|
||||
@ -261,6 +264,7 @@ struct AudioOptions {
|
||||
Settable<int> adjust_agc_delta;
|
||||
Settable<bool> experimental_agc;
|
||||
Settable<bool> experimental_aec;
|
||||
Settable<bool> experimental_ns;
|
||||
Settable<bool> aec_dump;
|
||||
Settable<bool> experimental_acm;
|
||||
// Note that tx_agc_* only applies to non-experimental AGC.
|
||||
@ -763,8 +767,10 @@ struct VideoSenderInfo : public MediaSenderInfo {
|
||||
: packets_cached(0),
|
||||
firs_rcvd(0),
|
||||
nacks_rcvd(0),
|
||||
frame_width(0),
|
||||
frame_height(0),
|
||||
input_frame_width(0),
|
||||
input_frame_height(0),
|
||||
send_frame_width(0),
|
||||
send_frame_height(0),
|
||||
framerate_input(0),
|
||||
framerate_sent(0),
|
||||
nominal_bitrate(0),
|
||||
@ -780,8 +786,10 @@ struct VideoSenderInfo : public MediaSenderInfo {
|
||||
int packets_cached;
|
||||
int firs_rcvd;
|
||||
int nacks_rcvd;
|
||||
int frame_width;
|
||||
int frame_height;
|
||||
int input_frame_width;
|
||||
int input_frame_height;
|
||||
int send_frame_width;
|
||||
int send_frame_height;
|
||||
int framerate_input;
|
||||
int framerate_sent;
|
||||
int nominal_bitrate;
|
||||
|
@ -162,8 +162,9 @@ float VideoAdapter::FindLowerScale(int width, int height,
|
||||
VideoAdapter::VideoAdapter()
|
||||
: output_num_pixels_(INT_MAX),
|
||||
scale_third_(false),
|
||||
frames_(0),
|
||||
adapted_frames_(0),
|
||||
frames_in_(0),
|
||||
frames_out_(0),
|
||||
frames_scaled_(0),
|
||||
adaption_changes_(0),
|
||||
previous_width_(0),
|
||||
previous_height_(0),
|
||||
@ -177,9 +178,13 @@ VideoAdapter::~VideoAdapter() {
|
||||
|
||||
void VideoAdapter::SetInputFormat(const VideoFormat& format) {
|
||||
talk_base::CritScope cs(&critical_section_);
|
||||
int64 old_input_interval = input_format_.interval;
|
||||
input_format_ = format;
|
||||
output_format_.interval = talk_base::_max(
|
||||
output_format_.interval, input_format_.interval);
|
||||
if (old_input_interval != input_format_.interval) {
|
||||
LOG(LS_INFO) << "VAdapt Input Interval: " << input_format_.interval;
|
||||
}
|
||||
}
|
||||
|
||||
void CoordinatedVideoAdapter::SetInputFormat(const VideoFormat& format) {
|
||||
@ -207,10 +212,14 @@ void CoordinatedVideoAdapter::SetInputFormat(const VideoFormat& format) {
|
||||
|
||||
void VideoAdapter::SetOutputFormat(const VideoFormat& format) {
|
||||
talk_base::CritScope cs(&critical_section_);
|
||||
int64 old_output_interval = output_format_.interval;
|
||||
output_format_ = format;
|
||||
output_num_pixels_ = output_format_.width * output_format_.height;
|
||||
output_format_.interval = talk_base::_max(
|
||||
output_format_.interval, input_format_.interval);
|
||||
if (old_output_interval != output_format_.interval) {
|
||||
LOG(LS_INFO) << "VAdapt Output Interval: " << output_format_.interval;
|
||||
}
|
||||
}
|
||||
|
||||
const VideoFormat& VideoAdapter::input_format() {
|
||||
@ -245,7 +254,7 @@ bool VideoAdapter::AdaptFrame(const VideoFrame* in_frame,
|
||||
if (!in_frame || !out_frame) {
|
||||
return false;
|
||||
}
|
||||
++frames_;
|
||||
++frames_in_;
|
||||
|
||||
// Update input to actual frame dimensions.
|
||||
VideoFormat format(static_cast<int>(in_frame->GetWidth()),
|
||||
@ -273,6 +282,23 @@ bool VideoAdapter::AdaptFrame(const VideoFrame* in_frame,
|
||||
}
|
||||
}
|
||||
if (should_drop) {
|
||||
// Show VAdapt log every 90 frames dropped. (3 seconds)
|
||||
// TODO(fbarchard): Consider GetLogSeverity() to change interval to less
|
||||
// for LS_VERBOSE and more for LS_INFO.
|
||||
bool show = (frames_in_ - frames_out_) % 90 == 0;
|
||||
|
||||
if (show) {
|
||||
// TODO(fbarchard): Reduce to LS_VERBOSE when adapter info is not needed
|
||||
// in default calls.
|
||||
LOG(LS_INFO) << "VAdapt Drop Frame: " << frames_scaled_
|
||||
<< " / " << frames_out_
|
||||
<< " / " << frames_in_
|
||||
<< " Changes: " << adaption_changes_
|
||||
<< " Input: " << in_frame->GetWidth()
|
||||
<< "x" << in_frame->GetHeight()
|
||||
<< " i" << input_format_.interval
|
||||
<< " Output: i" << output_format_.interval;
|
||||
}
|
||||
*out_frame = NULL;
|
||||
return true;
|
||||
}
|
||||
@ -289,19 +315,22 @@ bool VideoAdapter::AdaptFrame(const VideoFrame* in_frame,
|
||||
}
|
||||
|
||||
if (!StretchToOutputFrame(in_frame)) {
|
||||
LOG(LS_VERBOSE) << "VAdapt Stretch Failed.";
|
||||
return false;
|
||||
}
|
||||
|
||||
*out_frame = output_frame_.get();
|
||||
|
||||
// Show VAdapt log every 300 frames. (10 seconds)
|
||||
// TODO(fbarchard): Consider GetLogSeverity() to change interval to less
|
||||
// for LS_VERBOSE and more for LS_INFO.
|
||||
bool show = frames_ % 300 == 0;
|
||||
++frames_out_;
|
||||
if (in_frame->GetWidth() != (*out_frame)->GetWidth() ||
|
||||
in_frame->GetHeight() != (*out_frame)->GetHeight()) {
|
||||
++adapted_frames_;
|
||||
++frames_scaled_;
|
||||
}
|
||||
// Show VAdapt log every 90 frames output. (3 seconds)
|
||||
// TODO(fbarchard): Consider GetLogSeverity() to change interval to less
|
||||
// for LS_VERBOSE and more for LS_INFO.
|
||||
bool show = (frames_out_) % 90 == 0;
|
||||
|
||||
// TODO(fbarchard): LOG the previous output resolution and track input
|
||||
// resolution changes as well. Consider dropping the statistics into their
|
||||
// own class which could be queried publically.
|
||||
@ -315,14 +344,17 @@ bool VideoAdapter::AdaptFrame(const VideoFrame* in_frame,
|
||||
if (show) {
|
||||
// TODO(fbarchard): Reduce to LS_VERBOSE when adapter info is not needed
|
||||
// in default calls.
|
||||
LOG(LS_INFO) << "VAdapt Frame: " << adapted_frames_
|
||||
<< " / " << frames_
|
||||
LOG(LS_INFO) << "VAdapt Frame: " << frames_scaled_
|
||||
<< " / " << frames_out_
|
||||
<< " / " << frames_in_
|
||||
<< " Changes: " << adaption_changes_
|
||||
<< " Input: " << in_frame->GetWidth()
|
||||
<< "x" << in_frame->GetHeight()
|
||||
<< " i" << input_format_.interval
|
||||
<< " Scale: " << scale
|
||||
<< " Output: " << (*out_frame)->GetWidth()
|
||||
<< "x" << (*out_frame)->GetHeight()
|
||||
<< " i" << output_format_.interval
|
||||
<< " Changed: " << (changed ? "true" : "false");
|
||||
}
|
||||
previous_width_ = (*out_frame)->GetWidth();
|
||||
|
@ -87,8 +87,9 @@ class VideoAdapter {
|
||||
VideoFormat output_format_;
|
||||
int output_num_pixels_;
|
||||
bool scale_third_; // True if adapter allows scaling to 1/3 and 2/3.
|
||||
int frames_; // Number of input frames.
|
||||
int adapted_frames_; // Number of frames scaled.
|
||||
int frames_in_; // Number of input frames.
|
||||
int frames_out_; // Number of output frames.
|
||||
int frames_scaled_; // Number of frames scaled.
|
||||
int adaption_changes_; // Number of changes in scale factor.
|
||||
size_t previous_width_; // Previous adapter output width.
|
||||
size_t previous_height_; // Previous adapter output height.
|
||||
|
@ -790,8 +790,8 @@ class VideoMediaChannelTest : public testing::Test,
|
||||
EXPECT_EQ(0.0, info.senders[0].fraction_lost);
|
||||
EXPECT_EQ(0, info.senders[0].firs_rcvd);
|
||||
EXPECT_EQ(0, info.senders[0].nacks_rcvd);
|
||||
EXPECT_EQ(DefaultCodec().width, info.senders[0].frame_width);
|
||||
EXPECT_EQ(DefaultCodec().height, info.senders[0].frame_height);
|
||||
EXPECT_EQ(DefaultCodec().width, info.senders[0].send_frame_width);
|
||||
EXPECT_EQ(DefaultCodec().height, info.senders[0].send_frame_height);
|
||||
EXPECT_GT(info.senders[0].framerate_input, 0);
|
||||
EXPECT_GT(info.senders[0].framerate_sent, 0);
|
||||
|
||||
@ -848,8 +848,8 @@ class VideoMediaChannelTest : public testing::Test,
|
||||
EXPECT_EQ(0.0, info.senders[0].fraction_lost);
|
||||
EXPECT_EQ(0, info.senders[0].firs_rcvd);
|
||||
EXPECT_EQ(0, info.senders[0].nacks_rcvd);
|
||||
EXPECT_EQ(DefaultCodec().width, info.senders[0].frame_width);
|
||||
EXPECT_EQ(DefaultCodec().height, info.senders[0].frame_height);
|
||||
EXPECT_EQ(DefaultCodec().width, info.senders[0].send_frame_width);
|
||||
EXPECT_EQ(DefaultCodec().height, info.senders[0].send_frame_height);
|
||||
EXPECT_GT(info.senders[0].framerate_input, 0);
|
||||
EXPECT_GT(info.senders[0].framerate_sent, 0);
|
||||
|
||||
@ -918,12 +918,12 @@ class VideoMediaChannelTest : public testing::Test,
|
||||
info.senders[0].packets_sent + info.senders[1].packets_sent);
|
||||
EXPECT_EQ(1U, info.senders[0].ssrcs().size());
|
||||
EXPECT_EQ(1234U, info.senders[0].ssrcs()[0]);
|
||||
EXPECT_EQ(DefaultCodec().width, info.senders[0].frame_width);
|
||||
EXPECT_EQ(DefaultCodec().height, info.senders[0].frame_height);
|
||||
EXPECT_EQ(DefaultCodec().width, info.senders[0].send_frame_width);
|
||||
EXPECT_EQ(DefaultCodec().height, info.senders[0].send_frame_height);
|
||||
EXPECT_EQ(1U, info.senders[1].ssrcs().size());
|
||||
EXPECT_EQ(5678U, info.senders[1].ssrcs()[0]);
|
||||
EXPECT_EQ(kTestWidth, info.senders[1].frame_width);
|
||||
EXPECT_EQ(kTestHeight, info.senders[1].frame_height);
|
||||
EXPECT_EQ(kTestWidth, info.senders[1].send_frame_width);
|
||||
EXPECT_EQ(kTestHeight, info.senders[1].send_frame_height);
|
||||
// The capturer must be unregistered here as it runs out of it's scope next.
|
||||
EXPECT_TRUE(channel_->SetCapturer(5678, NULL));
|
||||
}
|
||||
|
@ -50,10 +50,10 @@ bool V4LLookup::CheckIsV4L2Device(const std::string& device_path) {
|
||||
|
||||
is_v4l2 = true;
|
||||
} else {
|
||||
LOG(LS_ERROR) << "VIDIOC_QUERYCAP failed for " << device_path;
|
||||
LOG_ERRNO(LS_ERROR) << "VIDIOC_QUERYCAP failed for " << device_path;
|
||||
}
|
||||
} else {
|
||||
LOG(LS_ERROR) << "Failed to open " << device_path;
|
||||
LOG_ERRNO(LS_ERROR) << "Failed to open " << device_path;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -83,13 +83,18 @@ class FakeWebRtcVideoCaptureModule : public webrtc::VideoCaptureModule {
|
||||
virtual int32_t RegisterCaptureDataCallback(
|
||||
webrtc::VideoCaptureDataCallback& callback) {
|
||||
callback_ = &callback;
|
||||
return 0;
|
||||
}
|
||||
virtual void DeRegisterCaptureDataCallback() { callback_ = NULL; }
|
||||
virtual void RegisterCaptureCallback(webrtc::VideoCaptureFeedBack& callback) {
|
||||
// Not implemented.
|
||||
virtual int32_t DeRegisterCaptureDataCallback() {
|
||||
callback_ = NULL;
|
||||
return 0;
|
||||
}
|
||||
virtual void DeRegisterCaptureCallback() {
|
||||
// Not implemented.
|
||||
virtual int32_t RegisterCaptureCallback(
|
||||
webrtc::VideoCaptureFeedBack& callback) {
|
||||
return -1; // not implemented
|
||||
}
|
||||
virtual int32_t DeRegisterCaptureCallback() {
|
||||
return 0;
|
||||
}
|
||||
virtual int32_t SetCaptureDelay(int32_t delay) {
|
||||
delay_ = delay;
|
||||
|
@ -2300,8 +2300,18 @@ bool WebRtcVideoMediaChannel::GetStats(VideoMediaInfo* info) {
|
||||
sinfo.firs_rcvd = -1;
|
||||
sinfo.nacks_rcvd = -1;
|
||||
sinfo.rtt_ms = -1;
|
||||
sinfo.frame_width = static_cast<int>(channel_stream_info->width());
|
||||
sinfo.frame_height = static_cast<int>(channel_stream_info->height());
|
||||
sinfo.input_frame_width = static_cast<int>(channel_stream_info->width());
|
||||
sinfo.input_frame_height =
|
||||
static_cast<int>(channel_stream_info->height());
|
||||
webrtc::VideoCodec vie_codec;
|
||||
if (engine()->vie()->codec()->GetSendCodec(channel_id, vie_codec) == 0) {
|
||||
sinfo.send_frame_width = vie_codec.width;
|
||||
sinfo.send_frame_height = vie_codec.height;
|
||||
} else {
|
||||
sinfo.send_frame_width = -1;
|
||||
sinfo.send_frame_height = -1;
|
||||
LOG_RTCERR1(GetSendCodec, channel_id);
|
||||
}
|
||||
sinfo.framerate_input = channel_stream_info->framerate();
|
||||
sinfo.framerate_sent = send_channel->encoder_observer()->framerate();
|
||||
sinfo.nominal_bitrate = send_channel->encoder_observer()->bitrate();
|
||||
|
@ -229,6 +229,7 @@ static AudioOptions GetDefaultEngineOptions() {
|
||||
options.adjust_agc_delta.Set(0);
|
||||
options.experimental_agc.Set(false);
|
||||
options.experimental_aec.Set(false);
|
||||
options.experimental_ns.Set(false);
|
||||
options.aec_dump.Set(false);
|
||||
options.experimental_acm.Set(false);
|
||||
return options;
|
||||
@ -717,6 +718,7 @@ bool WebRtcVoiceEngine::ApplyOptions(const AudioOptions& options_in) {
|
||||
options.typing_detection.Set(false);
|
||||
options.experimental_agc.Set(false);
|
||||
options.experimental_aec.Set(false);
|
||||
options.experimental_ns.Set(false);
|
||||
#endif
|
||||
|
||||
LOG(LS_INFO) << "Applying audio options: " << options.ToString();
|
||||
@ -804,6 +806,25 @@ bool WebRtcVoiceEngine::ApplyOptions(const AudioOptions& options_in) {
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USE_WEBRTC_DEV_BRANCH
|
||||
bool experimental_ns;
|
||||
if (options.experimental_ns.Get(&experimental_ns)) {
|
||||
webrtc::AudioProcessing* audioproc =
|
||||
voe_wrapper_->base()->audio_processing();
|
||||
// We check audioproc for the benefit of tests, since FakeWebRtcVoiceEngine
|
||||
// returns NULL on audio_processing().
|
||||
if (audioproc) {
|
||||
if (audioproc->EnableExperimentalNs(experimental_ns) == -1) {
|
||||
LOG_RTCERR1(EnableExperimentalNs, experimental_ns);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
LOG(LS_VERBOSE) << "Experimental noise suppression set to "
|
||||
<< experimental_ns;
|
||||
}
|
||||
}
|
||||
#endif // USE_WEBRTC_DEV_BRANCH
|
||||
|
||||
bool highpass_filter;
|
||||
if (options.highpass_filter.Get(&highpass_filter)) {
|
||||
if (voep->EnableHighPassFilter(highpass_filter) == -1) {
|
||||
|
@ -328,7 +328,7 @@ void UDPPort::OnStunBindingRequestSucceeded(
|
||||
// related address is local socket address.
|
||||
set_related_address(socket_->GetLocalAddress());
|
||||
AddAddress(stun_addr, socket_->GetLocalAddress(), UDP_PROTOCOL_NAME,
|
||||
STUN_PORT_TYPE, ICE_TYPE_PREFERENCE_PRFLX, false);
|
||||
STUN_PORT_TYPE, ICE_TYPE_PREFERENCE_SRFLX, false);
|
||||
}
|
||||
SetResult(true);
|
||||
}
|
||||
|
@ -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,30 +1196,7 @@ 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() {
|
||||
@ -1528,10 +1204,10 @@ void BaseChannel::FlushRtcpMessages() {
|
||||
// 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);
|
||||
|
@ -248,12 +248,6 @@ class BaseChannel
|
||||
SrtpFilter* srtp_filter() { return &srtp_filter_; }
|
||||
bool rtcp() const { return rtcp_; }
|
||||
|
||||
void Send(uint32 id, talk_base::MessageData* pdata = NULL);
|
||||
void Post(uint32 id, talk_base::MessageData* pdata = NULL);
|
||||
void PostDelayed(int cmsDelay, uint32 id = 0,
|
||||
talk_base::MessageData* pdata = NULL);
|
||||
void Clear(uint32 id = talk_base::MQID_ANY,
|
||||
talk_base::MessageList* removed = NULL);
|
||||
void FlushRtcpMessages();
|
||||
|
||||
// NetworkInterface implementation, called by MediaEngine
|
||||
@ -346,6 +340,12 @@ class BaseChannel
|
||||
virtual void OnConnectionMonitorUpdate(SocketMonitor* monitor,
|
||||
const std::vector<ConnectionInfo>& infos) = 0;
|
||||
|
||||
// Helper function for invoking bool-returning methods on the worker thread.
|
||||
template <class FunctorT>
|
||||
bool InvokeOnWorker(const FunctorT& functor) {
|
||||
return worker_thread_->Invoke<bool>(functor);
|
||||
}
|
||||
|
||||
private:
|
||||
sigslot::signal3<const void*, size_t, bool> SignalSendPacketPreCrypto;
|
||||
sigslot::signal3<const void*, size_t, bool> SignalSendPacketPostCrypto;
|
||||
@ -470,7 +470,6 @@ class VoiceChannel : public BaseChannel {
|
||||
bool SetRingbackTone_w(const void* buf, int len);
|
||||
bool PlayRingbackTone_w(uint32 ssrc, bool play, bool loop);
|
||||
void HandleEarlyMediaTimeout();
|
||||
bool CanInsertDtmf_w();
|
||||
bool InsertDtmf_w(uint32 ssrc, int event, int duration, int flags);
|
||||
bool SetOutputScaling_w(uint32 ssrc, double left, double right);
|
||||
bool GetStats_w(VoiceMediaInfo* stats);
|
||||
@ -485,9 +484,6 @@ class VoiceChannel : public BaseChannel {
|
||||
void OnVoiceChannelError(uint32 ssrc, VoiceMediaChannel::Error error);
|
||||
void SendLastMediaError();
|
||||
void OnSrtpError(uint32 ssrc, SrtpFilter::Mode mode, SrtpFilter::Error error);
|
||||
// Configuration and setting.
|
||||
bool SetChannelOptions_w(const AudioOptions& options);
|
||||
bool SetRenderer_w(uint32 ssrc, AudioRenderer* renderer, bool is_local);
|
||||
|
||||
static const int kEarlyMediaTimeout = 1000;
|
||||
bool received_media_;
|
||||
@ -557,7 +553,7 @@ class VideoChannel : public BaseChannel {
|
||||
|
||||
private:
|
||||
typedef std::map<uint32, VideoCapturer*> ScreencastMap;
|
||||
struct ScreencastDetailsMessageData;
|
||||
struct ScreencastDetailsData;
|
||||
|
||||
// overrides from BaseChannel
|
||||
virtual void ChangeState();
|
||||
@ -568,22 +564,13 @@ class VideoChannel : public BaseChannel {
|
||||
virtual bool SetRemoteContent_w(const MediaContentDescription* content,
|
||||
ContentAction action,
|
||||
std::string* error_desc);
|
||||
void SendIntraFrame_w() {
|
||||
media_channel()->SendIntraFrame();
|
||||
}
|
||||
void RequestIntraFrame_w() {
|
||||
media_channel()->RequestIntraFrame();
|
||||
}
|
||||
|
||||
bool ApplyViewRequest_w(const ViewRequest& request);
|
||||
void SetRenderer_w(uint32 ssrc, VideoRenderer* renderer);
|
||||
|
||||
VideoCapturer* AddScreencast_w(uint32 ssrc, const ScreencastId& id);
|
||||
bool SetCapturer_w(uint32 ssrc, VideoCapturer* capturer);
|
||||
bool RemoveScreencast_w(uint32 ssrc);
|
||||
void OnScreencastWindowEvent_s(uint32 ssrc, talk_base::WindowEvent we);
|
||||
bool IsScreencasting_w() const;
|
||||
void ScreencastDetails_w(ScreencastDetailsMessageData* d) const;
|
||||
void GetScreencastDetails_w(ScreencastDetailsData* d) const;
|
||||
void SetScreenCaptureFactory_w(
|
||||
ScreenCapturerFactory* screencapture_factory);
|
||||
bool GetStats_w(VideoMediaInfo* stats);
|
||||
@ -601,8 +588,6 @@ class VideoChannel : public BaseChannel {
|
||||
|
||||
void OnVideoChannelError(uint32 ssrc, VideoMediaChannel::Error error);
|
||||
void OnSrtpError(uint32 ssrc, SrtpFilter::Mode mode, SrtpFilter::Error error);
|
||||
// Configuration and setting.
|
||||
bool SetChannelOptions_w(const VideoOptions& options);
|
||||
|
||||
VoiceChannel* voice_channel_;
|
||||
VideoRenderer* renderer_;
|
||||
|
Loading…
x
Reference in New Issue
Block a user