1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
  137
  138
  139
  140
  141
  142
  143
  144
  145
  146
  147

content / browser / media / midi_host.h [blame]

// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CONTENT_BROWSER_MEDIA_MIDI_HOST_H_
#define CONTENT_BROWSER_MEDIA_MIDI_HOST_H_

#include <stddef.h>
#include <stdint.h>

#include <memory>
#include <vector>

#include "base/gtest_prod_util.h"
#include "base/memory/raw_ptr.h"
#include "base/synchronization/lock.h"
#include "base/thread_annotations.h"
#include "base/tuple.h"
#include "content/common/content_export.h"
#include "content/public/browser/browser_message_filter.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "media/midi/midi_manager.h"
#include "media/midi/midi_service.mojom.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/remote.h"

namespace midi {
class MidiService;
class MidiMessageQueue;
}  // namespace midi

namespace content {

class CONTENT_EXPORT MidiHost : public midi::MidiManagerClient,
                                public midi::mojom::MidiSessionProvider,
                                public midi::mojom::MidiSession {
 public:
  MidiHost(const MidiHost&) = delete;
  MidiHost& operator=(const MidiHost&) = delete;

  ~MidiHost() override;

  // Creates an instance of MidiHost and binds |receiver| to the instance using
  // a self owned receiver. Should be called on the IO thread.
  static void BindReceiver(
      int render_process_id,
      midi::MidiService* midi_service,
      mojo::PendingReceiver<midi::mojom::MidiSessionProvider> receiver);

  // MidiManagerClient implementation. These methods can be called on any thread
  // by platform specific implementations of MidiManager, so use locks
  // appropriately.
  void CompleteStartSession(midi::mojom::Result result) override;
  void AddInputPort(const midi::mojom::PortInfo& info) override;
  void AddOutputPort(const midi::mojom::PortInfo& info) override;
  void SetInputPortState(uint32_t port, midi::mojom::PortState state) override;
  void SetOutputPortState(uint32_t port, midi::mojom::PortState state) override;
  void ReceiveMidiData(uint32_t port,
                       const uint8_t* data,
                       size_t length,
                       base::TimeTicks timestamp) override;
  void AccumulateMidiBytesSent(size_t n) override;
  void Detach() override;

  // midi::mojom::MidiSessionProvider implementation.
  void StartSession(
      mojo::PendingReceiver<midi::mojom::MidiSession> session_receiver,
      mojo::PendingRemote<midi::mojom::MidiSessionClient> client) override;

  // midi::mojom::MidiSession implementation.
  void SendData(uint32_t port,
                const std::vector<uint8_t>& data,
                base::TimeTicks timestamp) override;

 protected:
  MidiHost(int renderer_process_id, midi::MidiService* midi_service);

  void SetHasMidiPermissionForTesting(bool value) {
    has_midi_permission_ = value;
  }

 private:
  // Use this to call methods on |midi_client_|. It makes sure that midi_client_
  // is only accessed on the IO thread.
  template <typename Method, typename... Params>
  void CallClient(Method method, Params... params);

  void EndSession();

  const int renderer_process_id_;

  // Represents if the renderer has a permission to send/receive MIDI messages.
  bool has_midi_permission_;

  // Represents if the renderer has a permission to send/receive MIDI SysEX
  // messages.
  bool has_midi_sysex_permission_;

  // |midi_service_| manages a MidiManager instance that talks to
  // platform-specific MIDI APIs.  It can be nullptr after detached.
  raw_ptr<midi::MidiService> midi_service_;

  // Buffers where data sent from each MIDI input port is stored.
  std::vector<std::unique_ptr<midi::MidiMessageQueue>> received_messages_queues_
      GUARDED_BY(messages_queues_lock_);

  // Protects access to |received_messages_queues_|;
  base::Lock messages_queues_lock_;

  // The number of bytes sent to the platform-specific MIDI sending
  // system, but not yet completed.
  size_t sent_bytes_in_flight_ GUARDED_BY(in_flight_lock_);

  // The number of bytes successfully sent since the last time
  // we've acknowledged back to the renderer.
  size_t bytes_sent_since_last_acknowledgement_;

  // Protects access to |sent_bytes_in_flight_|.
  base::Lock in_flight_lock_;

  // How many output port exists.
  uint32_t output_port_count_ GUARDED_BY(output_port_count_lock_);

  // Protects access to |output_port_count_|.
  base::Lock output_port_count_lock_;

  // Stores a session request sent from the renderer until CompleteStartSession
  // is called.
  mojo::PendingReceiver<midi::mojom::MidiSession> pending_session_receiver_;

  // Bound on the IO thread if a session is successfully started by MidiService.
  mojo::Receiver<midi::mojom::MidiSession> midi_session_{this};

  // Bound on the IO thread and should only be called there. Use CallClient to
  // call midi::mojom::MidiSessionClient methods.
  mojo::Remote<midi::mojom::MidiSessionClient> midi_client_;

  // WeakPtr factory for CallClient callbacks.
  base::WeakPtrFactory<MidiHost> weak_ptr_factory_{this};
};

}  // namespace content

#endif  // CONTENT_BROWSER_MEDIA_MIDI_HOST_H_