// 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 #include #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 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 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> frame_events, scoped_ptr> 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, 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 event) const { for (RawEventSubscriber* s : subscribers_) s->OnReceiveFrameEvent(*event); } void LogEventDispatcher::Impl::DispatchPacketEvent( scoped_ptr event) const { for (RawEventSubscriber* s : subscribers_) s->OnReceivePacketEvent(*event); } void LogEventDispatcher::Impl::DispatchBatchOfEvents( scoped_ptr> frame_events, scoped_ptr> 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