blob: 2d05a16c36db1b82e68581418f9432c1270a03d2 [file] [log] [blame]
// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "media/cast/logging/log_event_dispatcher.h"
#include <utility>
#include "base/containers/contains.h"
#include "base/functional/bind.h"
#include "base/functional/callback_helpers.h"
#include "base/location.h"
#include "base/ranges/algorithm.h"
#include "base/synchronization/waitable_event.h"
#include "media/cast/cast_environment.h"
namespace media {
namespace cast {
LogEventDispatcher::LogEventDispatcher(CastEnvironment* env)
: env_(env), impl_(new Impl()) {
DCHECK(env_);
}
LogEventDispatcher::~LogEventDispatcher() = default;
void LogEventDispatcher::DispatchFrameEvent(
std::unique_ptr<FrameEvent> event) const {
if (env_->CurrentlyOn(CastEnvironment::MAIN)) {
impl_->DispatchFrameEvent(std::move(event));
} else {
env_->PostTask(CastEnvironment::MAIN, FROM_HERE,
base::BindOnce(&LogEventDispatcher::Impl::DispatchFrameEvent,
impl_, std::move(event)));
}
}
void LogEventDispatcher::DispatchPacketEvent(
std::unique_ptr<PacketEvent> event) const {
if (env_->CurrentlyOn(CastEnvironment::MAIN)) {
impl_->DispatchPacketEvent(std::move(event));
} else {
env_->PostTask(
CastEnvironment::MAIN, FROM_HERE,
base::BindOnce(&LogEventDispatcher::Impl::DispatchPacketEvent, impl_,
std::move(event)));
}
}
void LogEventDispatcher::DispatchBatchOfEvents(
std::unique_ptr<std::vector<FrameEvent>> frame_events,
std::unique_ptr<std::vector<PacketEvent>> packet_events) const {
if (env_->CurrentlyOn(CastEnvironment::MAIN)) {
impl_->DispatchBatchOfEvents(std::move(frame_events),
std::move(packet_events));
} else {
env_->PostTask(
CastEnvironment::MAIN, FROM_HERE,
base::BindOnce(&LogEventDispatcher::Impl::DispatchBatchOfEvents, impl_,
std::move(frame_events), std::move(packet_events)));
}
}
void LogEventDispatcher::Subscribe(RawEventSubscriber* subscriber) {
if (env_->CurrentlyOn(CastEnvironment::MAIN)) {
impl_->Subscribe(subscriber);
} else {
env_->PostTask(CastEnvironment::MAIN, FROM_HERE,
base::BindOnce(&LogEventDispatcher::Impl::Subscribe, impl_,
subscriber));
}
}
void LogEventDispatcher::Unsubscribe(RawEventSubscriber* subscriber) {
if (env_->CurrentlyOn(CastEnvironment::MAIN)) {
impl_->Unsubscribe(subscriber);
} else {
// This method, once it returns, guarantees |subscriber| will not receive
// any more events. Therefore, when called on a thread other than the
// CastEnvironment's MAIN thread, block until the unsubscribe task
// completes.
struct Helper {
static void UnsubscribeAndSignal(const scoped_refptr<Impl>& impl,
RawEventSubscriber* subscriber,
base::WaitableEvent* done) {
impl->Unsubscribe(subscriber);
done->Signal();
}
};
base::WaitableEvent done(base::WaitableEvent::ResetPolicy::MANUAL,
base::WaitableEvent::InitialState::NOT_SIGNALED);
CHECK(env_->PostTask(CastEnvironment::MAIN, FROM_HERE,
base::BindOnce(&Helper::UnsubscribeAndSignal, impl_,
subscriber, &done)));
done.Wait();
}
}
LogEventDispatcher::Impl::Impl() = default;
LogEventDispatcher::Impl::~Impl() {
DCHECK(subscribers_.empty());
}
void LogEventDispatcher::Impl::DispatchFrameEvent(
std::unique_ptr<FrameEvent> event) const {
for (RawEventSubscriber* s : subscribers_)
s->OnReceiveFrameEvent(*event);
}
void LogEventDispatcher::Impl::DispatchPacketEvent(
std::unique_ptr<PacketEvent> event) const {
for (RawEventSubscriber* s : subscribers_)
s->OnReceivePacketEvent(*event);
}
void LogEventDispatcher::Impl::DispatchBatchOfEvents(
std::unique_ptr<std::vector<FrameEvent>> frame_events,
std::unique_ptr<std::vector<PacketEvent>> packet_events) const {
for (RawEventSubscriber* s : subscribers_) {
for (const FrameEvent& e : *frame_events)
s->OnReceiveFrameEvent(e);
for (const PacketEvent& e : *packet_events)
s->OnReceivePacketEvent(e);
}
}
void LogEventDispatcher::Impl::Subscribe(RawEventSubscriber* subscriber) {
DCHECK(!base::Contains(subscribers_, subscriber));
subscribers_.push_back(subscriber);
}
void LogEventDispatcher::Impl::Unsubscribe(RawEventSubscriber* subscriber) {
const auto it = base::ranges::find(subscribers_, subscriber);
DCHECK(it != subscribers_.end());
subscribers_.erase(it);
}
} // namespace cast
} // namespace media