| // Copyright 2015 The Chromium Authors. All rights reserved. |
| // 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 <algorithm> |
| #include <utility> |
| |
| #include "base/bind.h" |
| #include "base/bind_helpers.h" |
| #include "base/location.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() {} |
| |
| void LogEventDispatcher::DispatchFrameEvent( |
| scoped_ptr<FrameEvent> event) const { |
| if (env_->CurrentlyOn(CastEnvironment::MAIN)) { |
| impl_->DispatchFrameEvent(std::move(event)); |
| } else { |
| env_->PostTask(CastEnvironment::MAIN, FROM_HERE, |
| base::Bind(&LogEventDispatcher::Impl::DispatchFrameEvent, |
| impl_, base::Passed(&event))); |
| } |
| } |
| |
| void LogEventDispatcher::DispatchPacketEvent( |
| scoped_ptr<PacketEvent> event) const { |
| if (env_->CurrentlyOn(CastEnvironment::MAIN)) { |
| impl_->DispatchPacketEvent(std::move(event)); |
| } else { |
| env_->PostTask(CastEnvironment::MAIN, FROM_HERE, |
| base::Bind(&LogEventDispatcher::Impl::DispatchPacketEvent, |
| impl_, base::Passed(&event))); |
| } |
| } |
| |
| void LogEventDispatcher::DispatchBatchOfEvents( |
| scoped_ptr<std::vector<FrameEvent>> frame_events, |
| scoped_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::Bind(&LogEventDispatcher::Impl::DispatchBatchOfEvents, impl_, |
| base::Passed(&frame_events), base::Passed(&packet_events))); |
| } |
| } |
| |
| void LogEventDispatcher::Subscribe(RawEventSubscriber* subscriber) { |
| if (env_->CurrentlyOn(CastEnvironment::MAIN)) { |
| impl_->Subscribe(subscriber); |
| } else { |
| env_->PostTask( |
| CastEnvironment::MAIN, FROM_HERE, |
| base::Bind(&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(true, false); |
| CHECK(env_->PostTask( |
| CastEnvironment::MAIN, FROM_HERE, |
| base::Bind(&Helper::UnsubscribeAndSignal, impl_, subscriber, &done))); |
| done.Wait(); |
| } |
| } |
| |
| LogEventDispatcher::Impl::Impl() {} |
| |
| LogEventDispatcher::Impl::~Impl() { |
| DCHECK(subscribers_.empty()); |
| } |
| |
| void LogEventDispatcher::Impl::DispatchFrameEvent( |
| scoped_ptr<FrameEvent> event) const { |
| for (RawEventSubscriber* s : subscribers_) |
| s->OnReceiveFrameEvent(*event); |
| } |
| |
| void LogEventDispatcher::Impl::DispatchPacketEvent( |
| scoped_ptr<PacketEvent> event) const { |
| for (RawEventSubscriber* s : subscribers_) |
| s->OnReceivePacketEvent(*event); |
| } |
| |
| void LogEventDispatcher::Impl::DispatchBatchOfEvents( |
| scoped_ptr<std::vector<FrameEvent>> frame_events, |
| scoped_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(std::find(subscribers_.begin(), subscribers_.end(), subscriber) == |
| subscribers_.end()); |
| subscribers_.push_back(subscriber); |
| } |
| |
| void LogEventDispatcher::Impl::Unsubscribe(RawEventSubscriber* subscriber) { |
| const auto it = |
| std::find(subscribers_.begin(), subscribers_.end(), subscriber); |
| DCHECK(it != subscribers_.end()); |
| subscribers_.erase(it); |
| } |
| |
| } // namespace cast |
| } // namespace media |