Add some instrumentation for jank in URLRequest::Start.
[chromium-blink-merge.git] / media / midi / midi_manager_alsa.h
bloba041004dcd8a2bf7579e5fde6cd558f1448c14b6
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #ifndef MEDIA_MIDI_MIDI_MANAGER_ALSA_H_
6 #define MEDIA_MIDI_MIDI_MANAGER_ALSA_H_
8 #include <alsa/asoundlib.h>
9 #include <map>
10 #include <vector>
12 #include "base/basictypes.h"
13 #include "base/gtest_prod_util.h"
14 #include "base/memory/scoped_ptr.h"
15 #include "base/memory/scoped_vector.h"
16 #include "base/stl_util.h"
17 #include "base/synchronization/lock.h"
18 #include "base/threading/thread.h"
19 #include "base/values.h"
20 #include "media/midi/midi_manager.h"
22 namespace media {
24 class MEDIA_EXPORT MidiManagerAlsa final : public MidiManager {
25 public:
26 MidiManagerAlsa();
27 ~MidiManagerAlsa() override;
29 // MidiManager implementation.
30 void StartInitialization() override;
31 void DispatchSendMidiData(MidiManagerClient* client,
32 uint32 port_index,
33 const std::vector<uint8>& data,
34 double timestamp) override;
36 private:
37 friend class MidiManagerAlsaTest;
38 FRIEND_TEST_ALL_PREFIXES(MidiManagerAlsaTest, ExtractManufacturer);
39 FRIEND_TEST_ALL_PREFIXES(MidiManagerAlsaTest, ToMidiPortState);
41 class MidiPort {
42 public:
43 enum class Type { kInput, kOutput };
45 MidiPort(const std::string& path,
46 const std::string& id,
47 int client_id,
48 int port_id,
49 int midi_device,
50 const std::string& client_name,
51 const std::string& port_name,
52 const std::string& manufacturer,
53 const std::string& version,
54 Type type);
55 ~MidiPort();
57 // Gets a Value representation of this object, suitable for serialization.
58 scoped_ptr<base::Value> Value() const;
60 // Gets a string version of Value in JSON format.
61 std::string JSONValue() const;
63 // Gets an opaque identifier for this object, suitable for using as the id
64 // field in MidiPort.id on the web. Note that this string does not store
65 // the full state.
66 std::string OpaqueKey() const;
68 // Checks for equality for connected ports.
69 bool MatchConnected(const MidiPort& query) const;
70 // Checks for equality for kernel cards with id, pass 1.
71 bool MatchCardPass1(const MidiPort& query) const;
72 // Checks for equality for kernel cards with id, pass 2.
73 bool MatchCardPass2(const MidiPort& query) const;
74 // Checks for equality for non-card clients, pass 1.
75 bool MatchNoCardPass1(const MidiPort& query) const;
76 // Checks for equality for non-card clients, pass 2.
77 bool MatchNoCardPass2(const MidiPort& query) const;
79 // accessors
80 std::string path() const { return path_; }
81 std::string id() const { return id_; }
82 std::string client_name() const { return client_name_; }
83 std::string port_name() const { return port_name_; }
84 std::string manufacturer() const { return manufacturer_; }
85 std::string version() const { return version_; }
86 int client_id() const { return client_id_; }
87 int port_id() const { return port_id_; }
88 int midi_device() const { return midi_device_; }
89 Type type() const { return type_; }
90 uint32 web_port_index() const { return web_port_index_; }
91 bool connected() const { return connected_; }
93 // mutators
94 void set_web_port_index(uint32 web_port_index) {
95 web_port_index_ = web_port_index;
97 void set_connected(bool connected) { connected_ = connected; }
98 void Update(const std::string& path,
99 int client_id,
100 int port_id,
101 const std::string& client_name,
102 const std::string& port_name,
103 const std::string& manufacturer,
104 const std::string& version) {
105 path_ = path;
106 client_id_ = client_id;
107 port_id_ = port_id;
108 client_name_ = client_name;
109 port_name_ = port_name;
110 manufacturer_ = manufacturer;
111 version_ = version;
114 private:
115 // Immutable properties.
116 const std::string id_;
117 const int midi_device_;
119 const Type type_;
121 // Mutable properties. These will get updated as ports move around or
122 // drivers change.
123 std::string path_;
124 int client_id_;
125 int port_id_;
126 std::string client_name_;
127 std::string port_name_;
128 std::string manufacturer_;
129 std::string version_;
131 // Index for MidiManager.
132 uint32 web_port_index_;
134 // Port is present in the ALSA system.
135 bool connected_;
137 DISALLOW_COPY_AND_ASSIGN(MidiPort);
140 class MidiPortStateBase {
141 public:
142 typedef ScopedVector<MidiPort>::iterator iterator;
144 virtual ~MidiPortStateBase();
146 // Given a port, finds a port in the internal store.
147 iterator Find(const MidiPort& port);
149 // Given a port, finds a connected port, using exact matching.
150 iterator FindConnected(const MidiPort& port);
152 // Given a port, finds a disconnected port, using heuristic matching.
153 iterator FindDisconnected(const MidiPort& port);
155 iterator begin() { return ports_.begin(); }
156 iterator end() { return ports_.end(); }
158 protected:
159 MidiPortStateBase();
161 ScopedVector<MidiPort>* ports();
163 private:
164 ScopedVector<MidiPort> ports_;
166 DISALLOW_COPY_AND_ASSIGN(MidiPortStateBase);
169 class TemporaryMidiPortState final : public MidiPortStateBase {
170 public:
171 // Removes a port from the list without deleting it.
172 iterator weak_erase(iterator position) {
173 return ports()->weak_erase(position);
176 void Insert(scoped_ptr<MidiPort> port);
179 class MidiPortState final : public MidiPortStateBase {
180 public:
181 MidiPortState();
183 // Inserts a port. Returns web_port_index.
184 uint32 Insert(scoped_ptr<MidiPort> port);
186 private:
187 uint32 num_input_ports_;
188 uint32 num_output_ports_;
191 class AlsaSeqState {
192 public:
193 enum class PortDirection { kInput, kOutput, kDuplex };
195 AlsaSeqState();
196 ~AlsaSeqState();
198 void ClientStart(int client_id,
199 const std::string& client_name,
200 snd_seq_client_type_t type);
201 bool ClientStarted(int client_id);
202 void ClientExit(int client_id);
203 void PortStart(int client_id,
204 int port_id,
205 const std::string& port_name,
206 PortDirection direction,
207 bool midi);
208 void PortExit(int client_id, int port_id);
209 snd_seq_client_type_t ClientType(int client_id) const;
210 scoped_ptr<TemporaryMidiPortState> ToMidiPortState();
212 private:
213 class Port {
214 public:
215 Port(const std::string& name, PortDirection direction, bool midi);
216 ~Port();
218 std::string name() const;
219 PortDirection direction() const;
220 // True if this port is a MIDI port, instead of another kind of ALSA port.
221 bool midi() const;
223 private:
224 const std::string name_;
225 const PortDirection direction_;
226 const bool midi_;
228 DISALLOW_COPY_AND_ASSIGN(Port);
231 class Client {
232 public:
233 typedef std::map<int, Port*> PortMap;
235 Client(const std::string& name, snd_seq_client_type_t type);
236 ~Client();
238 std::string name() const;
239 snd_seq_client_type_t type() const;
240 void AddPort(int addr, scoped_ptr<Port> port);
241 void RemovePort(int addr);
242 PortMap::const_iterator begin() const;
243 PortMap::const_iterator end() const;
245 private:
246 const std::string name_;
247 const snd_seq_client_type_t type_;
248 PortMap ports_;
249 STLValueDeleter<PortMap> ports_deleter_;
251 DISALLOW_COPY_AND_ASSIGN(Client);
254 typedef std::map<int, Client*> ClientMap;
256 ClientMap clients_;
257 STLValueDeleter<ClientMap> clients_deleter_;
259 DISALLOW_COPY_AND_ASSIGN(AlsaSeqState);
262 typedef base::hash_map<int, uint32> SourceMap;
263 typedef base::hash_map<uint32, int> OutPortMap;
265 // Extracts the manufacturer using heuristics and a variety of sources.
266 static std::string ExtractManufacturerString(
267 const std::string& udev_id_vendor,
268 const std::string& udev_id_vendor_id,
269 const std::string& udev_id_vendor_from_database,
270 const std::string& alsa_name,
271 const std::string& alsa_longname);
273 // An internal callback that runs on MidiSendThread.
274 void SendMidiData(uint32 port_index, const std::vector<uint8>& data);
276 void ScheduleEventLoop();
277 void EventLoop();
278 void ProcessSingleEvent(snd_seq_event_t* event, double timestamp);
279 void ProcessClientStartEvent(int client_id);
280 void ProcessPortStartEvent(const snd_seq_addr_t& addr);
281 void ProcessClientExitEvent(const snd_seq_addr_t& addr);
282 void ProcessPortExitEvent(const snd_seq_addr_t& addr);
284 // Updates port_state_ and Web MIDI state from alsa_seq_state_.
285 void UpdatePortStateAndGenerateEvents();
287 // Enumerates ports. Call once after subscribing to the announce port.
288 void EnumerateAlsaPorts();
289 // Returns true if successful.
290 bool CreateAlsaOutputPort(uint32 port_index, int client_id, int port_id);
291 void DeleteAlsaOutputPort(uint32 port_index);
292 // Returns true if successful.
293 bool Subscribe(uint32 port_index, int client_id, int port_id);
295 AlsaSeqState alsa_seq_state_;
296 MidiPortState port_state_;
298 // ALSA seq handles.
299 snd_seq_t* in_client_;
300 int in_client_id_;
301 snd_seq_t* out_client_;
302 int out_client_id_;
304 // One input port, many output ports.
305 int in_port_id_;
306 OutPortMap out_ports_; // guarded by out_ports_lock_
307 base::Lock out_ports_lock_; // guards out_ports_
309 // Mapping from ALSA client:port to our index.
310 SourceMap source_map_;
312 // ALSA event -> MIDI coder.
313 snd_midi_event_t* decoder_;
315 base::Thread send_thread_;
316 base::Thread event_thread_;
318 bool event_thread_shutdown_; // guarded by shutdown_lock_
319 base::Lock shutdown_lock_; // guards event_thread_shutdown_
321 DISALLOW_COPY_AND_ASSIGN(MidiManagerAlsa);
324 } // namespace media
326 #endif // MEDIA_MIDI_MIDI_MANAGER_ALSA_H_