summaryrefslogtreecommitdiffstats
path: root/dom/midi/MIDIPlatformService.h
blob: 36a1ea1296d389c5783d26f574766e7fdfddfe42 (plain)
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
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef mozilla_dom_MIDIPlatformService_h
#define mozilla_dom_MIDIPlatformService_h

#include "nsClassHashtable.h"
#include "mozilla/Mutex.h"
#include "mozilla/dom/MIDIPortBinding.h"
#include "nsHashKeys.h"

// XXX Avoid including this here by moving function implementations to the cpp
// file.
#include "mozilla/dom/MIDIMessageQueue.h"

namespace mozilla::dom {

class MIDIManagerParent;
class MIDIPortParent;
class MIDIMessage;
class MIDIMessageQueue;
class MIDIPortInfo;

/**
 * Base class for platform specific MIDI implementations. Handles aggregation of
 * IPC service objects, as well as sending/receiving updates about port
 * connection events and messages.
 *
 */
class MIDIPlatformService {
 public:
  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MIDIPlatformService);
  // Adds info about MIDI Port that has been connected.
  void AddPortInfo(MIDIPortInfo& aPortInfo);

  // Removes info of MIDI Port that has been disconnected.
  void RemovePortInfo(MIDIPortInfo& aPortInfo);

  // Adds a newly created manager protocol object to manager array.
  void AddManager(MIDIManagerParent* aManager);

  // Removes a deleted manager protocol object from manager array.
  void RemoveManager(MIDIManagerParent* aManager);

  // Adds a newly created port protocol object to port array.
  void AddPort(MIDIPortParent* aPort);

  // Removes a deleted port protocol object from port array.
  void RemovePort(MIDIPortParent* aPort);

  // Platform specific init function.
  virtual void Init() = 0;

  // Forces the implementation to refresh the port list.
  virtual void Refresh() = 0;

  // Platform specific MIDI port opening function.
  virtual void Open(MIDIPortParent* aPort) = 0;

  // Clears all queued MIDI messages for a port.
  void Clear(MIDIPortParent* aPort);

  // Puts in a request to destroy the singleton MIDIPlatformService object.
  // Object will only be destroyed if there are no more MIDIManager and MIDIPort
  // protocols left to communicate with.
  void MaybeStop();

  // Initializes statics on startup.
  static void InitStatics();

  // Returns the MIDI Task Queue.
  static nsISerialEventTarget* OwnerThread();

  // Asserts that we're on the above task queue.
  static void AssertThread() {
    MOZ_DIAGNOSTIC_ASSERT(OwnerThread()->IsOnCurrentThread());
  }

  // True if service is live.
  static bool IsRunning();

  // Returns a pointer to the MIDIPlatformService object, creating it and
  // starting the platform specific service if it is not currently running.
  static MIDIPlatformService* Get();

  // Sends a list of all currently connected ports in order to populate a new
  // MIDIAccess object.
  void SendPortList();

  // Receives a new set of messages from an MIDI Input Port, and checks their
  // validity.
  void CheckAndReceive(const nsAString& aPortID,
                       const nsTArray<MIDIMessage>& aMsgs);

  // Sends connection/disconnect/open/closed/etc status updates about a MIDI
  // Port to all port listeners.
  void UpdateStatus(MIDIPortParent* aPort,
                    const MIDIPortDeviceState& aDeviceState,
                    const MIDIPortConnectionState& aConnectionState);

  // Adds outgoing messages to the sorted message queue, for sending later.
  void QueueMessages(const nsAString& aId, nsTArray<MIDIMessage>& aMsgs);

  // Clears all messages later than now, sends all outgoing message scheduled
  // before/at now, and schedules MIDI Port connection closing.
  void Close(MIDIPortParent* aPort);

  // Returns whether there are currently any MIDI devices.
  bool HasDevice() { return !mPortInfo.IsEmpty(); }

 protected:
  MIDIPlatformService();
  virtual ~MIDIPlatformService();
  // Platform specific MIDI service shutdown method.
  virtual void Stop() = 0;

  // When device state of a MIDI Port changes, broadcast to all IPC port
  // objects.
  void BroadcastState(const MIDIPortInfo& aPortInfo,
                      const MIDIPortDeviceState& aState);

  // Platform specific MIDI port closing function. Named "Schedule" due to the
  // fact that it needs to happen in the context of the I/O thread for the
  // platform MIDI implementation, and therefore will happen async.
  virtual void ScheduleClose(MIDIPortParent* aPort) = 0;

  // Platform specific MIDI message sending function. Named "Schedule" due to
  // the fact that it needs to happen in the context of the I/O thread for the
  // platform MIDI implementation, and therefore will happen async.
  virtual void ScheduleSend(const nsAString& aPortId) = 0;

  // Allows platform specific IO Threads to retrieve all messages to be sent.
  // Handles mutex locking.
  void GetMessages(const nsAString& aPortId, nsTArray<MIDIMessage>& aMsgs);

  // Allows platform specific IO Threads to retrieve all messages to be sent
  // before a certain timestamp. Handles mutex locking.
  void GetMessagesBefore(const nsAString& aPortId, const TimeStamp& aTimeStamp,
                         nsTArray<MIDIMessage>& aMsgs);

 private:
  // When the MIDIPlatformService is created, we need to know whether or not the
  // corresponding IPC MIDIManager objects have received the MIDIPort list after
  // it is populated. This is set to True when that is done, so we don't
  // constantly spam MIDIManagers with port lists.
  bool mHasSentPortList;

  // Array of MIDIManager IPC objects. This array manages the lifetime of
  // MIDIManager objects in the parent process, and IPC will call
  // RemoveManager() end lifetime when IPC channel is destroyed.
  nsTArray<RefPtr<MIDIManagerParent>> mManagers;

  // Array of information for currently connected Ports
  nsTArray<MIDIPortInfo> mPortInfo;

  // Array of MIDIPort IPC objects. May contain ports not listed in mPortInfo,
  // as we can hold port objects even after they are disconnected.
  //
  // TODO Split this into input and output ports. Will make life easier.
  nsTArray<RefPtr<MIDIPortParent>> mPorts;

  // Per-port message queue hashtable. Handles scheduling messages for sending.
  nsClassHashtable<nsStringHashKey, MIDIMessageQueue> mMessageQueues;

  // Mutex for managing access to message queue objects.
  Mutex mMessageQueueMutex MOZ_UNANNOTATED;
};

}  // namespace mozilla::dom

#endif  // mozilla_dom_MIDIPlatformService_h