blob: aeffeeb68f1ea8f91577ba65fd26563f66ab2648 [file] [log] [blame]
// 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 "chrome/browser/media/router/media_router_base.h"
#include "base/bind.h"
#include "base/guid.h"
#include "base/memory/ptr_util.h"
#include "base/stl_util.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/profiles/profile.h"
#include "content/public/browser/browser_thread.h"
namespace media_router {
// A MediaRoutesObserver that maintains state about the current set of media
// routes.
class MediaRouterBase::InternalMediaRoutesObserver
: public MediaRoutesObserver {
public:
explicit InternalMediaRoutesObserver(MediaRouter* router)
: MediaRoutesObserver(router), has_route(false) {}
~InternalMediaRoutesObserver() override {}
// MediaRoutesObserver
void OnRoutesUpdated(
const std::vector<MediaRoute>& routes,
const std::vector<MediaRoute::Id>& joinable_route_ids) override {
incognito_route_ids.clear();
// TODO(crbug.com/611486): Have the MRPM pass a list of joinable route ids
// via |joinable_route_ids|, and check here if it is non-empty.
has_route = !routes.empty();
for (const auto& route : routes) {
if (route.is_incognito())
incognito_route_ids.push_back(route.media_route_id());
}
}
bool has_route;
std::vector<MediaRoute::Id> incognito_route_ids;
private:
DISALLOW_COPY_AND_ASSIGN(InternalMediaRoutesObserver);
};
MediaRouterBase::~MediaRouterBase() {
CHECK(!internal_routes_observer_);
}
std::unique_ptr<PresentationConnectionStateSubscription>
MediaRouterBase::AddPresentationConnectionStateChangedCallback(
const MediaRoute::Id& route_id,
const content::PresentationConnectionStateChangedCallback& callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
auto* callbacks = presentation_connection_state_callbacks_.get(route_id);
if (!callbacks) {
callbacks = new PresentationConnectionStateChangedCallbacks;
callbacks->set_removal_callback(base::Bind(
&MediaRouterBase::OnPresentationConnectionStateCallbackRemoved,
base::Unretained(this), route_id));
presentation_connection_state_callbacks_.add(route_id,
base::WrapUnique(callbacks));
}
return callbacks->Add(callback);
}
void MediaRouterBase::OnIncognitoProfileShutdown() {
for (const auto& route_id : internal_routes_observer_->incognito_route_ids)
TerminateRoute(route_id);
}
MediaRouterBase::MediaRouterBase() : initialized_(false) {}
// static
std::string MediaRouterBase::CreatePresentationId() {
return "mr_" + base::GenerateGUID();
}
void MediaRouterBase::NotifyPresentationConnectionStateChange(
const MediaRoute::Id& route_id,
content::PresentationConnectionState state) {
// We should call NotifyPresentationConnectionClose() for the CLOSED state.
DCHECK_NE(state, content::PRESENTATION_CONNECTION_STATE_CLOSED);
auto* callbacks = presentation_connection_state_callbacks_.get(route_id);
if (!callbacks)
return;
callbacks->Notify(content::PresentationConnectionStateChangeInfo(state));
}
void MediaRouterBase::NotifyPresentationConnectionClose(
const MediaRoute::Id& route_id,
content::PresentationConnectionCloseReason reason,
const std::string& message) {
auto* callbacks = presentation_connection_state_callbacks_.get(route_id);
if (!callbacks)
return;
content::PresentationConnectionStateChangeInfo info(
content::PRESENTATION_CONNECTION_STATE_CLOSED);
info.close_reason = reason;
info.message = message;
callbacks->Notify(info);
}
bool MediaRouterBase::HasJoinableRoute() const {
return internal_routes_observer_->has_route;
}
void MediaRouterBase::Initialize() {
DCHECK(!initialized_);
// The observer calls virtual methods on MediaRouter; it must be created
// outside of the ctor
internal_routes_observer_.reset(new InternalMediaRoutesObserver(this));
initialized_ = true;
}
void MediaRouterBase::OnPresentationConnectionStateCallbackRemoved(
const MediaRoute::Id& route_id) {
auto* callbacks = presentation_connection_state_callbacks_.get(route_id);
if (callbacks && callbacks->empty())
presentation_connection_state_callbacks_.erase(route_id);
}
void MediaRouterBase::Shutdown() {
// The observer calls virtual methods on MediaRouter; it must be destroyed
// outside of the dtor
internal_routes_observer_.reset();
}
} // namespace media_router