chromium/chromecast/browser/audio_socket_broker.h

// 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_