// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROMECAST_BROWSER_AUDIO_SOCKET_BROKER_H_
#define CHROMECAST_BROWSER_AUDIO_SOCKET_BROKER_H_
#include <string>
#include "base/containers/flat_map.h"
#include "base/files/scoped_file.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "base/threading/sequence_bound.h"
#include "chromecast/common/mojom/audio_socket.mojom.h"
#include "content/public/browser/document_service.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
namespace base {
class SequencedTaskRunner;
} // namespace base
namespace net {
class UnixDomainClientSocket;
} // namespace net
namespace chromecast {
namespace media {
// Service hosted in the browser process to provide the descriptors of connected
// Unix Domain sockets for renderers and the audio output service. This service
// is necessary since renderers are not allowed to perform socket operations on
// some platforms (e.g. Android).
class AudioSocketBroker
: public ::content::DocumentService<mojom::AudioSocketBroker> {
public:
static void Create(content::RenderFrameHost* render_frame_host,
mojo::PendingReceiver<mojom::AudioSocketBroker> receiver);
static AudioSocketBroker& CreateForTesting(
content::RenderFrameHost& render_frame_host,
mojo::PendingReceiver<mojom::AudioSocketBroker> receiver,
const std::string& audio_output_service_path);
AudioSocketBroker(const AudioSocketBroker&) = delete;
AudioSocketBroker& operator=(const AudioSocketBroker&) = delete;
private:
class SocketFdConnection;
AudioSocketBroker(content::RenderFrameHost& render_frame_host,
mojo::PendingReceiver<mojom::AudioSocketBroker> receiver);
AudioSocketBroker(content::RenderFrameHost& render_frame_host,
mojo::PendingReceiver<mojom::AudioSocketBroker> receiver,
const std::string& audio_output_service_path);
~AudioSocketBroker() override;
// Helper struct which holds the information regarding a socket pair
// in the time between sending the socket to the renderer and the audio
// service.
struct PendingConnectionInfo {
PendingConnectionInfo(
base::SequenceBound<SocketFdConnection> arg_socket_fd_connection,
GetSocketDescriptorCallback arg_callback);
PendingConnectionInfo(const PendingConnectionInfo&) = delete;
PendingConnectionInfo& operator=(const PendingConnectionInfo&) = delete;
PendingConnectionInfo(PendingConnectionInfo&&);
PendingConnectionInfo& operator=(PendingConnectionInfo&&);
~PendingConnectionInfo();
base::SequenceBound<SocketFdConnection> socket_fd_connection;
GetSocketDescriptorCallback callback;
};
// mojom::AudioSocketBroker implementation:
void GetSocketDescriptor(GetSocketDescriptorCallback callback) override;
// Callback triggered when the socket handle is sent to the audio output
// service. |socket_fd| is the key to |pending_connection_infos_|.
// |pending_socket_fd| is invalid when connection fails.
void OnSocketHandleSentToAudioService(int socket_fd,
base::ScopedFD pending_socket_fd);
const std::string audio_output_service_path_;
scoped_refptr<base::SequencedTaskRunner> main_task_runner_;
base::flat_map<int /* socket FD */, PendingConnectionInfo>
pending_connection_infos_;
base::WeakPtrFactory<AudioSocketBroker> weak_factory_{this};
};
} // namespace media
} // namespace chromecast
#endif // CHROMECAST_BROWSER_AUDIO_SOCKET_BROKER_H_