blob: d0a5ee8197cbc7a92a92148f74837cf908b23220 [file] [log] [blame]
// Copyright 2018 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.
#ifndef OSP_PUBLIC_PRESENTATION_PRESENTATION_CONTROLLER_H_
#define OSP_PUBLIC_PRESENTATION_PRESENTATION_CONTROLLER_H_
#include <map>
#include <memory>
#include <string>
#include "absl/strings/string_view.h"
#include "absl/types/optional.h"
#include "osp/public/presentation/presentation_connection.h"
#include "osp/public/protocol_connection.h"
#include "osp/public/service_listener.h"
#include "platform/api/time.h"
#include "platform/base/error.h"
namespace openscreen {
namespace osp {
class UrlAvailabilityRequester;
class RequestDelegate {
public:
virtual ~RequestDelegate() = default;
virtual void OnConnection(std::unique_ptr<Connection> connection) = 0;
virtual void OnError(const Error& error) = 0;
};
class ReceiverObserver {
public:
virtual ~ReceiverObserver() = default;
// Called when there is an unrecoverable error in requesting availability.
// This means the availability is unknown and there is no further response to
// wait for.
virtual void OnRequestFailed(const std::string& presentation_url,
const std::string& service_id) = 0;
// Called when receivers compatible with |presentation_url| are known to be
// available.
virtual void OnReceiverAvailable(const std::string& presentation_url,
const std::string& service_id) = 0;
// Only called for |service_id| values previously advertised as available.
virtual void OnReceiverUnavailable(const std::string& presentation_url,
const std::string& service_id) = 0;
};
class Controller final : public ServiceListener::Observer,
public Connection::ParentDelegate {
public:
class ReceiverWatch {
public:
ReceiverWatch();
ReceiverWatch(Controller* controller,
const std::vector<std::string>& urls,
ReceiverObserver* observer);
ReceiverWatch(ReceiverWatch&&) noexcept;
~ReceiverWatch();
ReceiverWatch& operator=(ReceiverWatch);
explicit operator bool() const { return observer_; }
friend void swap(ReceiverWatch& a, ReceiverWatch& b);
private:
std::vector<std::string> urls_;
ReceiverObserver* observer_ = nullptr;
Controller* controller_ = nullptr;
};
class ConnectRequest {
public:
ConnectRequest();
ConnectRequest(Controller* controller,
const std::string& service_id,
bool is_reconnect,
absl::optional<uint64_t> request_id);
ConnectRequest(ConnectRequest&&) noexcept;
~ConnectRequest();
ConnectRequest& operator=(ConnectRequest);
explicit operator bool() const { return request_id_.has_value(); }
friend void swap(ConnectRequest& a, ConnectRequest& b);
private:
std::string service_id_;
bool is_reconnect_;
absl::optional<uint64_t> request_id_;
Controller* controller_;
};
explicit Controller(ClockNowFunctionPtr now_function);
~Controller();
// Requests receivers compatible with all urls in |urls| and registers
// |observer| for availability changes. The screens will be a subset of the
// screen list maintained by the ServiceListener. Returns an RAII object that
// tracks the registration.
ReceiverWatch RegisterReceiverWatch(const std::vector<std::string>& urls,
ReceiverObserver* observer);
// Requests that a new presentation be created on |service_id| using
// |presentation_url|, with the result passed to |delegate|.
// |conn_delegate| is passed to the resulting connection. The returned
// ConnectRequest object may be destroyed before any |delegate| methods are
// called to cancel the request.
ConnectRequest StartPresentation(const std::string& url,
const std::string& service_id,
RequestDelegate* delegate,
Connection::Delegate* conn_delegate);
// Requests reconnection to the presentation with the given id and URL running
// on |service_id|, with the result passed to |delegate|. |conn_delegate| is
// passed to the resulting connection. The returned ConnectRequest object may
// be destroyed before any |delegate| methods are called to cancel the
// request.
ConnectRequest ReconnectPresentation(const std::vector<std::string>& urls,
const std::string& presentation_id,
const std::string& service_id,
RequestDelegate* delegate,
Connection::Delegate* conn_delegate);
// Requests reconnection with a previously-connected connection. This both
// avoids having to respecify the parameters and connection delegate but also
// simplifies the implementation of the Presentation API requirement to return
// the same connection object where possible.
ConnectRequest ReconnectConnection(std::unique_ptr<Connection> connection,
RequestDelegate* delegate);
// Connection::ParentDelegate overrides.
Error CloseConnection(Connection* connection,
Connection::CloseReason reason) override;
// Also called by the embedder to report that a presentation has been
// terminated.
Error OnPresentationTerminated(const std::string& presentation_id,
TerminationReason reason) override;
void OnConnectionDestroyed(Connection* connection) override;
// Returns an empty string if no such presentation ID is found.
std::string GetServiceIdForPresentationId(
const std::string& presentation_id) const;
ProtocolConnection* GetConnectionRequestGroupStream(
const std::string& service_id);
// TODO(btolsch): still used?
void SetConnectionRequestGroupStreamForTest(
const std::string& service_id,
std::unique_ptr<ProtocolConnection> stream);
private:
class TerminationListener;
class MessageGroupStreams;
struct ControlledPresentation {
std::string service_id;
std::string url;
std::vector<Connection*> connections;
};
static std::string MakePresentationId(const std::string& url,
const std::string& service_id);
void AddConnection(Connection* connection);
void OpenConnection(uint64_t connection_id,
uint64_t endpoint_id,
const std::string& service_id,
RequestDelegate* request_delegate,
std::unique_ptr<Connection>&& connection,
std::unique_ptr<ProtocolConnection>&& stream);
void TerminatePresentationById(const std::string& presentation_id);
// Cancels compatible receiver monitoring for the given |urls|, |observer|
// pair.
void CancelReceiverWatch(const std::vector<std::string>& urls,
ReceiverObserver* observer);
// Cancels a presentation connect request for the given |request_id| if one is
// pending.
void CancelConnectRequest(const std::string& service_id,
bool is_reconnect,
uint64_t request_id);
// ServiceListener::Observer overrides.
void OnStarted() override;
void OnStopped() override;
void OnSuspended() override;
void OnSearching() override;
void OnReceiverAdded(const ServiceInfo& info) override;
void OnReceiverChanged(const ServiceInfo& info) override;
void OnReceiverRemoved(const ServiceInfo& info) override;
void OnAllReceiversRemoved() override;
void OnError(ServiceListenerError) override;
void OnMetrics(ServiceListener::Metrics) override;
std::map<std::string, uint64_t> next_connection_id_;
std::map<std::string, ControlledPresentation> presentations_;
std::unique_ptr<ConnectionManager> connection_manager_;
std::unique_ptr<UrlAvailabilityRequester> availability_requester_;
std::map<std::string, IPEndpoint> receiver_endpoints_;
std::map<std::string, std::unique_ptr<MessageGroupStreams>> group_streams_;
std::map<std::string, std::unique_ptr<TerminationListener>>
termination_listener_by_id_;
};
} // namespace osp
} // namespace openscreen
#endif // OSP_PUBLIC_PRESENTATION_PRESENTATION_CONTROLLER_H_