Add support for WeakPtr<T>

The implementation is borrowed from Chromium.

Also change use of raw pointers in VideoSendStreamImpl to use WeakPtr<>

BUG= webrtc:6289

Review-Url: https://codereview.webrtc.org/2367853002
Cr-Commit-Position: refs/heads/master@{#14468}
This commit is contained in:
perkj 2016-10-03 00:30:04 -07:00 committed by Commit bot
parent fa10b557d9
commit 8ff860a35d
7 changed files with 622 additions and 17 deletions

View File

@ -439,6 +439,7 @@ if (rtc_include_tests) {
"base/timeutils_unittest.cc",
"base/urlencode_unittest.cc",
"base/versionparsing_unittest.cc",
"base/weak_ptr_unittest.cc",
# TODO(ronghuawu): Reenable this test.
# "windowpicker_unittest.cc",

View File

@ -210,6 +210,8 @@ rtc_static_library("rtc_task_queue") {
"sequenced_task_checker.h",
"sequenced_task_checker_impl.cc",
"sequenced_task_checker_impl.h",
"weak_ptr.cc",
"weak_ptr.h",
]
if (build_with_chromium) {

View File

@ -167,6 +167,8 @@
'sequenced_task_checker.h',
'sequenced_task_checker_impl.cc',
'sequenced_task_checker_impl.h',
'weak_ptr.cc',
'weak_ptr.h',
],
'conditions': [
['build_with_chromium==1', {

87
webrtc/base/weak_ptr.cc Normal file
View File

@ -0,0 +1,87 @@
/*
* Copyright 2016 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/base/weak_ptr.h"
// The implementation is borrowed from chromium except that it does not
// implement SupportsWeakPtr.
namespace rtc {
namespace internal {
WeakReference::Flag::Flag() : is_valid_(true) {
// Flags only become bound when checked for validity, or invalidated,
// so that we can check that later validity/invalidation operations on
// the same Flag take place on the same sequence.
checker_.Detach();
}
void WeakReference::Flag::Invalidate() {
RTC_DCHECK(checker_.CalledSequentially())
<< "WeakPtrs must be invalidated on the same sequence.";
is_valid_ = false;
}
bool WeakReference::Flag::IsValid() const {
RTC_DCHECK(checker_.CalledSequentially())
<< "WeakPtrs must be checked on the same sequence.";
return is_valid_;
}
WeakReference::Flag::~Flag() {}
WeakReference::WeakReference() {}
WeakReference::WeakReference(const Flag* flag) : flag_(flag) {}
WeakReference::~WeakReference() {}
WeakReference::WeakReference(WeakReference&& other) = default;
WeakReference::WeakReference(const WeakReference& other) = default;
bool WeakReference::is_valid() const {
return flag_.get() && flag_->IsValid();
}
WeakReferenceOwner::WeakReferenceOwner() {
checker_.Detach();
}
WeakReferenceOwner::~WeakReferenceOwner() {
RTC_DCHECK(checker_.CalledSequentially());
Invalidate();
}
WeakReference WeakReferenceOwner::GetRef() const {
RTC_DCHECK(checker_.CalledSequentially());
// If we hold the last reference to the Flag then create a new one.
if (!HasRefs())
flag_ = new RefCountedObject<WeakReference::Flag>();
return WeakReference(flag_.get());
}
void WeakReferenceOwner::Invalidate() {
RTC_DCHECK(checker_.CalledSequentially());
if (flag_.get()) {
flag_->Invalidate();
flag_ = NULL;
}
}
WeakPtrBase::WeakPtrBase() {}
WeakPtrBase::~WeakPtrBase() {}
WeakPtrBase::WeakPtrBase(const WeakReference& ref) : ref_(ref) {}
} // namespace internal
} // namespace rtc

272
webrtc/base/weak_ptr.h Normal file
View File

@ -0,0 +1,272 @@
/*
* Copyright 2016 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_BASE_WEAK_PTR_H_
#define WEBRTC_BASE_WEAK_PTR_H_
#include <memory>
#include <utility>
#include "webrtc/base/refcount.h"
#include "webrtc/base/scoped_ref_ptr.h"
#include "webrtc/base/sequenced_task_checker.h"
// The implementation is borrowed from chromium except that it does not
// implement SupportsWeakPtr.
// Weak pointers are pointers to an object that do not affect its lifetime,
// and which may be invalidated (i.e. reset to nullptr) by the object, or its
// owner, at any time, most commonly when the object is about to be deleted.
// Weak pointers are useful when an object needs to be accessed safely by one
// or more objects other than its owner, and those callers can cope with the
// object vanishing and e.g. tasks posted to it being silently dropped.
// Reference-counting such an object would complicate the ownership graph and
// make it harder to reason about the object's lifetime.
// EXAMPLE:
//
// class Controller {
// public:
// Controller() : weak_factory_(this) {}
// void SpawnWorker() { Worker::StartNew(weak_factory_.GetWeakPtr()); }
// void WorkComplete(const Result& result) { ... }
// private:
// // Member variables should appear before the WeakPtrFactory, to ensure
// // that any WeakPtrs to Controller are invalidated before its members
// // variable's destructors are executed, rendering them invalid.
// WeakPtrFactory<Controller> weak_factory_;
// };
//
// class Worker {
// public:
// static void StartNew(const WeakPtr<Controller>& controller) {
// Worker* worker = new Worker(controller);
// // Kick off asynchronous processing...
// }
// private:
// Worker(const WeakPtr<Controller>& controller)
// : controller_(controller) {}
// void DidCompleteAsynchronousProcessing(const Result& result) {
// if (controller_)
// controller_->WorkComplete(result);
// }
// WeakPtr<Controller> controller_;
// };
//
// With this implementation a caller may use SpawnWorker() to dispatch multiple
// Workers and subsequently delete the Controller, without waiting for all
// Workers to have completed.
// ------------------------- IMPORTANT: Thread-safety -------------------------
// Weak pointers may be passed safely between threads, but must always be
// dereferenced and invalidated on the same TaskQueue or thread, otherwise
// checking the pointer would be racey.
//
// To ensure correct use, the first time a WeakPtr issued by a WeakPtrFactory
// is dereferenced, the factory and its WeakPtrs become bound to the calling
// TaskQueue/thread, and cannot be dereferenced or
// invalidated on any other TaskQueue/thread. Bound WeakPtrs can still be handed
// off to other TaskQueues, e.g. to use to post tasks back to object on the
// bound sequence.
//
// Thus, at least one WeakPtr object must exist and have been dereferenced on
// the correct thread to enforce that other WeakPtr objects will enforce they
// are used on the desired thread.
namespace rtc {
namespace internal {
class WeakReference {
public:
// Although Flag is bound to a specific sequence, it may be
// deleted from another via base::WeakPtr::~WeakPtr().
class Flag : public RefCountInterface {
public:
Flag();
void Invalidate();
bool IsValid() const;
private:
friend class RefCountedObject<Flag>;
~Flag() override;
SequencedTaskChecker checker_;
bool is_valid_;
};
WeakReference();
explicit WeakReference(const Flag* flag);
~WeakReference();
WeakReference(WeakReference&& other);
WeakReference(const WeakReference& other);
WeakReference& operator=(WeakReference&& other) = default;
WeakReference& operator=(const WeakReference& other) = default;
bool is_valid() const;
private:
scoped_refptr<const Flag> flag_;
};
class WeakReferenceOwner {
public:
WeakReferenceOwner();
~WeakReferenceOwner();
WeakReference GetRef() const;
bool HasRefs() const { return flag_.get() && !flag_->HasOneRef(); }
void Invalidate();
private:
SequencedTaskChecker checker_;
mutable scoped_refptr<RefCountedObject<WeakReference::Flag>> flag_;
};
// This class simplifies the implementation of WeakPtr's type conversion
// constructor by avoiding the need for a public accessor for ref_. A
// WeakPtr<T> cannot access the private members of WeakPtr<U>, so this
// base class gives us a way to access ref_ in a protected fashion.
class WeakPtrBase {
public:
WeakPtrBase();
~WeakPtrBase();
WeakPtrBase(const WeakPtrBase& other) = default;
WeakPtrBase(WeakPtrBase&& other) = default;
WeakPtrBase& operator=(const WeakPtrBase& other) = default;
WeakPtrBase& operator=(WeakPtrBase&& other) = default;
protected:
explicit WeakPtrBase(const WeakReference& ref);
WeakReference ref_;
};
} // namespace internal
template <typename T>
class WeakPtrFactory;
template <typename T>
class WeakPtr : public internal::WeakPtrBase {
public:
WeakPtr() : ptr_(nullptr) {}
// Allow conversion from U to T provided U "is a" T. Note that this
// is separate from the (implicit) copy and move constructors.
template <typename U>
WeakPtr(const WeakPtr<U>& other)
: internal::WeakPtrBase(other), ptr_(other.ptr_) {}
template <typename U>
WeakPtr(WeakPtr<U>&& other)
: internal::WeakPtrBase(std::move(other)), ptr_(other.ptr_) {}
T* get() const { return ref_.is_valid() ? ptr_ : nullptr; }
T& operator*() const {
RTC_DCHECK(get() != nullptr);
return *get();
}
T* operator->() const {
RTC_DCHECK(get() != nullptr);
return get();
}
void reset() {
ref_ = internal::WeakReference();
ptr_ = nullptr;
}
// Allow conditionals to test validity, e.g. if (weak_ptr) {...};
explicit operator bool() const { return get() != nullptr; }
private:
template <typename U>
friend class WeakPtr;
friend class WeakPtrFactory<T>;
WeakPtr(const internal::WeakReference& ref, T* ptr)
: internal::WeakPtrBase(ref), ptr_(ptr) {}
// This pointer is only valid when ref_.is_valid() is true. Otherwise, its
// value is undefined (as opposed to nullptr).
T* ptr_;
};
// Allow callers to compare WeakPtrs against nullptr to test validity.
template <class T>
bool operator!=(const WeakPtr<T>& weak_ptr, std::nullptr_t) {
return !(weak_ptr == nullptr);
}
template <class T>
bool operator!=(std::nullptr_t, const WeakPtr<T>& weak_ptr) {
return weak_ptr != nullptr;
}
template <class T>
bool operator==(const WeakPtr<T>& weak_ptr, std::nullptr_t) {
return weak_ptr.get() == nullptr;
}
template <class T>
bool operator==(std::nullptr_t, const WeakPtr<T>& weak_ptr) {
return weak_ptr == nullptr;
}
// A class may be composed of a WeakPtrFactory and thereby
// control how it exposes weak pointers to itself. This is helpful if you only
// need weak pointers within the implementation of a class. This class is also
// useful when working with primitive types. For example, you could have a
// WeakPtrFactory<bool> that is used to pass around a weak reference to a bool.
// Note that GetWeakPtr must be called on one and only one TaskQueue or thread
// and the WeakPtr must only be dereferenced and invalidated on that same
// TaskQueue/thread. A WeakPtr instance can be copied and posted to other
// sequences though as long as it is not dereferenced (WeakPtr<T>::get()).
template <class T>
class WeakPtrFactory {
public:
explicit WeakPtrFactory(T* ptr) : ptr_(ptr) {}
~WeakPtrFactory() { ptr_ = nullptr; }
WeakPtr<T> GetWeakPtr() {
RTC_DCHECK(ptr_);
return WeakPtr<T>(weak_reference_owner_.GetRef(), ptr_);
}
// Call this method to invalidate all existing weak pointers.
void InvalidateWeakPtrs() {
RTC_DCHECK(ptr_);
weak_reference_owner_.Invalidate();
}
// Call this method to determine if any weak pointers exist.
bool HasWeakPtrs() const {
RTC_DCHECK(ptr_);
return weak_reference_owner_.HasRefs();
}
private:
internal::WeakReferenceOwner weak_reference_owner_;
T* ptr_;
RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(WeakPtrFactory);
};
} // namespace rtc
#endif // WEBRTC_BASE_WEAK_PTR_H_

View File

@ -0,0 +1,233 @@
/*
* Copyright 2016 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <string>
#include "webrtc/base/gunit.h"
#include "webrtc/base/task_queue.h"
#include "webrtc/base/weak_ptr.h"
namespace rtc {
namespace {
struct Base {
std::string member;
};
struct Derived : public Base {};
struct Target {};
struct Arrow {
WeakPtr<Target> target;
};
struct TargetWithFactory : public Target {
TargetWithFactory() : factory(this) {}
WeakPtrFactory<Target> factory;
};
} // namespace
TEST(WeakPtrFactoryTest, Basic) {
int data;
WeakPtrFactory<int> factory(&data);
WeakPtr<int> ptr = factory.GetWeakPtr();
EXPECT_EQ(&data, ptr.get());
}
TEST(WeakPtrFactoryTest, Comparison) {
int data;
WeakPtrFactory<int> factory(&data);
WeakPtr<int> ptr = factory.GetWeakPtr();
WeakPtr<int> ptr2 = ptr;
EXPECT_EQ(ptr.get(), ptr2.get());
}
TEST(WeakPtrFactoryTest, Move) {
int data;
WeakPtrFactory<int> factory(&data);
WeakPtr<int> ptr = factory.GetWeakPtr();
WeakPtr<int> ptr2 = factory.GetWeakPtr();
WeakPtr<int> ptr3 = std::move(ptr2);
EXPECT_NE(ptr.get(), ptr2.get());
EXPECT_EQ(ptr.get(), ptr3.get());
}
TEST(WeakPtrFactoryTest, OutOfScope) {
WeakPtr<int> ptr;
EXPECT_EQ(nullptr, ptr.get());
{
int data;
WeakPtrFactory<int> factory(&data);
ptr = factory.GetWeakPtr();
EXPECT_EQ(&data, ptr.get());
}
EXPECT_EQ(nullptr, ptr.get());
}
TEST(WeakPtrFactoryTest, Multiple) {
WeakPtr<int> a, b;
{
int data;
WeakPtrFactory<int> factory(&data);
a = factory.GetWeakPtr();
b = factory.GetWeakPtr();
EXPECT_EQ(&data, a.get());
EXPECT_EQ(&data, b.get());
}
EXPECT_EQ(nullptr, a.get());
EXPECT_EQ(nullptr, b.get());
}
TEST(WeakPtrFactoryTest, MultipleStaged) {
WeakPtr<int> a;
{
int data;
WeakPtrFactory<int> factory(&data);
a = factory.GetWeakPtr();
{ WeakPtr<int> b = factory.GetWeakPtr(); }
EXPECT_NE(nullptr, a.get());
}
EXPECT_EQ(nullptr, a.get());
}
TEST(WeakPtrFactoryTest, Dereference) {
Base data;
data.member = "123456";
WeakPtrFactory<Base> factory(&data);
WeakPtr<Base> ptr = factory.GetWeakPtr();
EXPECT_EQ(&data, ptr.get());
EXPECT_EQ(data.member, (*ptr).member);
EXPECT_EQ(data.member, ptr->member);
}
TEST(WeakPtrFactoryTest, UpCast) {
Derived data;
WeakPtrFactory<Derived> factory(&data);
WeakPtr<Base> ptr = factory.GetWeakPtr();
ptr = factory.GetWeakPtr();
EXPECT_EQ(ptr.get(), &data);
}
TEST(WeakPtrTest, DefaultConstructor) {
WeakPtr<int> ptr;
EXPECT_EQ(nullptr, ptr.get());
}
TEST(WeakPtrFactoryTest, BooleanTesting) {
int data;
WeakPtrFactory<int> factory(&data);
WeakPtr<int> ptr_to_an_instance = factory.GetWeakPtr();
EXPECT_TRUE(ptr_to_an_instance);
EXPECT_FALSE(!ptr_to_an_instance);
if (ptr_to_an_instance) {
} else {
ADD_FAILURE() << "Pointer to an instance should result in true.";
}
if (!ptr_to_an_instance) { // check for operator!().
ADD_FAILURE() << "Pointer to an instance should result in !x being false.";
}
WeakPtr<int> null_ptr;
EXPECT_FALSE(null_ptr);
EXPECT_TRUE(!null_ptr);
if (null_ptr) {
ADD_FAILURE() << "Null pointer should result in false.";
}
if (!null_ptr) { // check for operator!().
} else {
ADD_FAILURE() << "Null pointer should result in !x being true.";
}
}
TEST(WeakPtrFactoryTest, ComparisonToNull) {
int data;
WeakPtrFactory<int> factory(&data);
WeakPtr<int> ptr_to_an_instance = factory.GetWeakPtr();
EXPECT_NE(nullptr, ptr_to_an_instance);
EXPECT_NE(ptr_to_an_instance, nullptr);
WeakPtr<int> null_ptr;
EXPECT_EQ(null_ptr, nullptr);
EXPECT_EQ(nullptr, null_ptr);
}
TEST(WeakPtrTest, InvalidateWeakPtrs) {
int data;
WeakPtrFactory<int> factory(&data);
WeakPtr<int> ptr = factory.GetWeakPtr();
EXPECT_EQ(&data, ptr.get());
EXPECT_TRUE(factory.HasWeakPtrs());
factory.InvalidateWeakPtrs();
EXPECT_EQ(nullptr, ptr.get());
EXPECT_FALSE(factory.HasWeakPtrs());
// Test that the factory can create new weak pointers after a
// InvalidateWeakPtrs call, and they remain valid until the next
// InvalidateWeakPtrs call.
WeakPtr<int> ptr2 = factory.GetWeakPtr();
EXPECT_EQ(&data, ptr2.get());
EXPECT_TRUE(factory.HasWeakPtrs());
factory.InvalidateWeakPtrs();
EXPECT_EQ(nullptr, ptr2.get());
EXPECT_FALSE(factory.HasWeakPtrs());
}
TEST(WeakPtrTest, HasWeakPtrs) {
int data;
WeakPtrFactory<int> factory(&data);
{
WeakPtr<int> ptr = factory.GetWeakPtr();
EXPECT_TRUE(factory.HasWeakPtrs());
}
EXPECT_FALSE(factory.HasWeakPtrs());
}
template <class T>
std::unique_ptr<T> NewObjectCreatedOnTaskQueue() {
std::unique_ptr<T> obj;
TaskQueue queue("NewObjectCreatedOnTaskQueue");
Event event(false, false);
queue.PostTask([&event, &obj] {
obj.reset(new T());
event.Set();
});
EXPECT_TRUE(event.Wait(1000));
return obj;
}
TEST(WeakPtrTest, ObjectAndWeakPtrOnDifferentThreads) {
// Test that it is OK to create an object with a WeakPtrFactory one thread,
// but use it on another. This tests that we do not trip runtime checks that
// ensure that a WeakPtr is not used by multiple threads.
std::unique_ptr<TargetWithFactory> target(
NewObjectCreatedOnTaskQueue<TargetWithFactory>());
WeakPtr<Target> weak_ptr = target->factory.GetWeakPtr();
EXPECT_EQ(target.get(), weak_ptr.get());
}
TEST(WeakPtrTest, WeakPtrInitiateAndUseOnDifferentThreads) {
// Test that it is OK to create an object that has a WeakPtr member on one
// thread, but use it on another. This tests that we do not trip runtime
// checks that ensure that a WeakPtr is not used by multiple threads.
std::unique_ptr<Arrow> arrow(NewObjectCreatedOnTaskQueue<Arrow>());
TargetWithFactory target;
arrow->target = target.factory.GetWeakPtr();
EXPECT_EQ(&target, arrow->target.get());
}
} // namespace rtc

View File

@ -20,6 +20,7 @@
#include "webrtc/base/file.h"
#include "webrtc/base/logging.h"
#include "webrtc/base/trace_event.h"
#include "webrtc/base/weak_ptr.h"
#include "webrtc/modules/bitrate_controller/include/bitrate_controller.h"
#include "webrtc/modules/congestion_controller/include/congestion_controller.h"
#include "webrtc/modules/pacing/packet_router.h"
@ -339,6 +340,14 @@ class VideoSendStreamImpl : public webrtc::BitrateAllocatorObserver,
// RtpRtcp modules, declared here as they use other members on construction.
const std::vector<RtpRtcp*> rtp_rtcp_modules_;
PayloadRouter payload_router_;
// |weak_ptr_| to our self. This is used since we can not call
// |weak_ptr_factory_.GetWeakPtr| from multiple sequences but it is ok to copy
// an existing WeakPtr.
rtc::WeakPtr<VideoSendStreamImpl> weak_ptr_;
// |weak_ptr_factory_| must be declared last to make sure all WeakPtr's are
// invalidated before any other members are destroyed.
rtc::WeakPtrFactory<VideoSendStreamImpl> weak_ptr_factory_;
};
// TODO(tommi): See if there's a more elegant way to create a task that creates
@ -431,12 +440,13 @@ class VideoSendStream::DestructAndGetRtpStateTask : public rtc::QueuedTask {
class VideoSendStreamImpl::CheckEncoderActivityTask : public rtc::QueuedTask {
public:
static const int kEncoderTimeOutMs = 2000;
explicit CheckEncoderActivityTask(VideoSendStreamImpl* send_stream)
: activity_(0), send_stream_(send_stream), timed_out_(false) {}
explicit CheckEncoderActivityTask(
const rtc::WeakPtr<VideoSendStreamImpl>& send_stream)
: activity_(0), send_stream_(std::move(send_stream)), timed_out_(false) {}
void Stop() {
RTC_CHECK(task_checker_.CalledSequentially());
send_stream_ = nullptr;
send_stream_.reset();
}
void UpdateEncoderActivity() {
@ -472,27 +482,28 @@ class VideoSendStreamImpl::CheckEncoderActivityTask : public rtc::QueuedTask {
volatile int activity_;
rtc::SequencedTaskChecker task_checker_;
VideoSendStreamImpl* send_stream_;
rtc::WeakPtr<VideoSendStreamImpl> send_stream_;
bool timed_out_;
};
class VideoSendStreamImpl::EncoderReconfiguredTask : public rtc::QueuedTask {
public:
EncoderReconfiguredTask(VideoSendStreamImpl* send_stream,
EncoderReconfiguredTask(const rtc::WeakPtr<VideoSendStreamImpl>& send_stream,
std::vector<VideoStream> streams,
int min_transmit_bitrate_bps)
: send_stream_(send_stream),
: send_stream_(std::move(send_stream)),
streams_(std::move(streams)),
min_transmit_bitrate_bps_(min_transmit_bitrate_bps) {}
private:
bool Run() override {
send_stream_->OnEncoderConfigurationChanged(std::move(streams_),
min_transmit_bitrate_bps_);
if (send_stream_)
send_stream_->OnEncoderConfigurationChanged(std::move(streams_),
min_transmit_bitrate_bps_);
return true;
}
VideoSendStreamImpl* send_stream_;
rtc::WeakPtr<VideoSendStreamImpl> send_stream_;
std::vector<VideoStream> streams_;
int min_transmit_bitrate_bps_;
};
@ -665,9 +676,11 @@ VideoSendStreamImpl::VideoSendStreamImpl(
congestion_controller_->GetRetransmissionRateLimiter(),
config_->rtp.ssrcs.size())),
payload_router_(rtp_rtcp_modules_,
config_->encoder_settings.payload_type) {
config_->encoder_settings.payload_type),
weak_ptr_factory_(this) {
RTC_DCHECK_RUN_ON(worker_queue_);
LOG(LS_INFO) << "VideoSendStreamInternal: " << config_->ToString();
weak_ptr_ = weak_ptr_factory_.GetWeakPtr();
module_process_thread_checker_.DetachFromThread();
RTC_DCHECK(!config_->rtp.ssrcs.empty());
@ -778,7 +791,7 @@ void VideoSendStreamImpl::Start() {
{
rtc::CritScope lock(&encoder_activity_crit_sect_);
RTC_DCHECK(!check_encoder_activity_task_);
check_encoder_activity_task_ = new CheckEncoderActivityTask(this);
check_encoder_activity_task_ = new CheckEncoderActivityTask(weak_ptr_);
worker_queue_->PostDelayedTask(
std::unique_ptr<rtc::QueuedTask>(check_encoder_activity_task_),
CheckEncoderActivityTask::kEncoderTimeOutMs);
@ -827,14 +840,9 @@ void VideoSendStreamImpl::OnEncoderConfigurationChanged(
std::vector<VideoStream> streams,
int min_transmit_bitrate_bps) {
if (!worker_queue_->IsCurrent()) {
// TODO(perkj): Using |this| in post is safe for now since destruction of
// VideoSendStreamImpl is synchronized in
// VideoSendStream::StopPermanentlyAndGetRtpStates. But we should really
// use some kind of weak_ptr to guarantee that VideoSendStreamImpl is still
// alive when this task runs.
worker_queue_->PostTask(
std::unique_ptr<rtc::QueuedTask>(new EncoderReconfiguredTask(
this, std::move(streams), min_transmit_bitrate_bps)));
weak_ptr_, std::move(streams), min_transmit_bitrate_bps)));
return;
}
RTC_DCHECK_GE(config_->rtp.ssrcs.size(), streams.size());