[Sync] Clear sync data and restart when enabling passphrase encryption
[chromium-blink-merge.git] / media / midi / midi_manager_alsa.h
blob8b211fe9df408ce942b2162d417d5dc6739ed708
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 "device/udev_linux/scoped_udev.h"
21 #include "media/midi/midi_export.h"
22 #include "media/midi/midi_manager.h"
24 namespace media {
25 namespace midi {
27 class MIDI_EXPORT MidiManagerAlsa final : public MidiManager {
28 public:
29 MidiManagerAlsa();
30 ~MidiManagerAlsa() override;
32 // MidiManager implementation.
33 void StartInitialization() override;
34 void DispatchSendMidiData(MidiManagerClient* client,
35 uint32 port_index,
36 const std::vector<uint8>& data,
37 double timestamp) override;
39 private:
40 friend class MidiManagerAlsaTest;
41 FRIEND_TEST_ALL_PREFIXES(MidiManagerAlsaTest, ExtractManufacturer);
42 FRIEND_TEST_ALL_PREFIXES(MidiManagerAlsaTest, ToMidiPortState);
44 class AlsaCard;
45 typedef std::map<int, AlsaCard*> AlsaCardMap;
47 class MidiPort {
48 public:
49 enum class Type { kInput, kOutput };
51 // The Id class is used to keep the multiple strings separate
52 // but compare them all together for equality purposes.
53 // The individual strings that make up the Id can theoretically contain
54 // arbitrary characters, so unfortunately there is no simple way to
55 // concatenate them into a single string.
56 class Id final {
57 public:
58 Id();
59 Id(const std::string& bus,
60 const std::string& vendor_id,
61 const std::string& model_id,
62 const std::string& usb_interface_num,
63 const std::string& serial);
64 Id(const Id&);
65 ~Id();
66 bool operator==(const Id&) const;
67 bool empty() const;
69 std::string bus() const { return bus_; }
70 std::string vendor_id() const { return vendor_id_; }
71 std::string model_id() const { return model_id_; }
72 std::string usb_interface_num() const { return usb_interface_num_; }
73 std::string serial() const { return serial_; }
75 private:
76 std::string bus_;
77 std::string vendor_id_;
78 std::string model_id_;
79 std::string usb_interface_num_;
80 std::string serial_;
83 MidiPort(const std::string& path,
84 const Id& id,
85 int client_id,
86 int port_id,
87 int midi_device,
88 const std::string& client_name,
89 const std::string& port_name,
90 const std::string& manufacturer,
91 const std::string& version,
92 Type type);
93 ~MidiPort();
95 // Gets a Value representation of this object, suitable for serialization.
96 scoped_ptr<base::Value> Value() const;
98 // Gets a string version of Value in JSON format.
99 std::string JSONValue() const;
101 // Gets an opaque identifier for this object, suitable for using as the id
102 // field in MidiPort.id on the web. Note that this string does not store
103 // the full state.
104 std::string OpaqueKey() const;
106 // Checks for equality for connected ports.
107 bool MatchConnected(const MidiPort& query) const;
108 // Checks for equality for kernel cards with id, pass 1.
109 bool MatchCardPass1(const MidiPort& query) const;
110 // Checks for equality for kernel cards with id, pass 2.
111 bool MatchCardPass2(const MidiPort& query) const;
112 // Checks for equality for non-card clients, pass 1.
113 bool MatchNoCardPass1(const MidiPort& query) const;
114 // Checks for equality for non-card clients, pass 2.
115 bool MatchNoCardPass2(const MidiPort& query) const;
117 // accessors
118 std::string path() const { return path_; }
119 Id id() const { return id_; }
120 std::string client_name() const { return client_name_; }
121 std::string port_name() const { return port_name_; }
122 std::string manufacturer() const { return manufacturer_; }
123 std::string version() const { return version_; }
124 int client_id() const { return client_id_; }
125 int port_id() const { return port_id_; }
126 int midi_device() const { return midi_device_; }
127 Type type() const { return type_; }
128 uint32 web_port_index() const { return web_port_index_; }
129 bool connected() const { return connected_; }
131 // mutators
132 void set_web_port_index(uint32 web_port_index) {
133 web_port_index_ = web_port_index;
135 void set_connected(bool connected) { connected_ = connected; }
136 void Update(const std::string& path,
137 int client_id,
138 int port_id,
139 const std::string& client_name,
140 const std::string& port_name,
141 const std::string& manufacturer,
142 const std::string& version) {
143 path_ = path;
144 client_id_ = client_id;
145 port_id_ = port_id;
146 client_name_ = client_name;
147 port_name_ = port_name;
148 manufacturer_ = manufacturer;
149 version_ = version;
152 private:
153 // Immutable properties.
154 const Id id_;
155 const int midi_device_;
157 const Type type_;
159 // Mutable properties. These will get updated as ports move around or
160 // drivers change.
161 std::string path_;
162 int client_id_;
163 int port_id_;
164 std::string client_name_;
165 std::string port_name_;
166 std::string manufacturer_;
167 std::string version_;
169 // Index for MidiManager.
170 uint32 web_port_index_;
172 // Port is present in the ALSA system.
173 bool connected_;
175 DISALLOW_COPY_AND_ASSIGN(MidiPort);
178 class MidiPortStateBase {
179 public:
180 typedef ScopedVector<MidiPort>::iterator iterator;
182 virtual ~MidiPortStateBase();
184 // Given a port, finds a port in the internal store.
185 iterator Find(const MidiPort& port);
187 // Given a port, finds a connected port, using exact matching.
188 iterator FindConnected(const MidiPort& port);
190 // Given a port, finds a disconnected port, using heuristic matching.
191 iterator FindDisconnected(const MidiPort& port);
193 iterator begin() { return ports_.begin(); }
194 iterator end() { return ports_.end(); }
196 protected:
197 MidiPortStateBase();
199 ScopedVector<MidiPort>* ports() { return &ports_; }
201 private:
202 ScopedVector<MidiPort> ports_;
204 DISALLOW_COPY_AND_ASSIGN(MidiPortStateBase);
207 class TemporaryMidiPortState final : public MidiPortStateBase {
208 public:
209 // Removes a port from the list without deleting it.
210 iterator weak_erase(iterator position) {
211 return ports()->weak_erase(position);
214 void Insert(scoped_ptr<MidiPort> port);
217 class MidiPortState final : public MidiPortStateBase {
218 public:
219 MidiPortState();
221 // Inserts a port. Returns web_port_index.
222 uint32 Insert(scoped_ptr<MidiPort> port);
224 private:
225 uint32 num_input_ports_;
226 uint32 num_output_ports_;
229 class AlsaSeqState {
230 public:
231 enum class PortDirection { kInput, kOutput, kDuplex };
233 AlsaSeqState();
234 ~AlsaSeqState();
236 void ClientStart(int client_id,
237 const std::string& client_name,
238 snd_seq_client_type_t type);
239 bool ClientStarted(int client_id);
240 void ClientExit(int client_id);
241 void PortStart(int client_id,
242 int port_id,
243 const std::string& port_name,
244 PortDirection direction,
245 bool midi);
246 void PortExit(int client_id, int port_id);
247 snd_seq_client_type_t ClientType(int client_id) const;
248 scoped_ptr<TemporaryMidiPortState> ToMidiPortState(
249 const AlsaCardMap& alsa_cards);
251 int card_client_count() { return card_client_count_; }
253 private:
254 class Port {
255 public:
256 Port(const std::string& name, PortDirection direction, bool midi);
257 ~Port();
259 std::string name() const { return name_; }
260 PortDirection direction() const { return direction_; }
261 // True if this port is a MIDI port, instead of another kind of ALSA port.
262 bool midi() const { return midi_; }
264 private:
265 const std::string name_;
266 const PortDirection direction_;
267 const bool midi_;
269 DISALLOW_COPY_AND_ASSIGN(Port);
272 class Client {
273 public:
274 typedef std::map<int, Port*> PortMap;
276 Client(const std::string& name, snd_seq_client_type_t type);
277 ~Client();
279 std::string name() const { return name_; }
280 snd_seq_client_type_t type() const { return type_; }
281 void AddPort(int addr, scoped_ptr<Port> port);
282 void RemovePort(int addr);
283 PortMap::const_iterator begin() const;
284 PortMap::const_iterator end() const;
286 private:
287 const std::string name_;
288 const snd_seq_client_type_t type_;
289 PortMap ports_;
290 STLValueDeleter<PortMap> ports_deleter_;
292 DISALLOW_COPY_AND_ASSIGN(Client);
295 typedef std::map<int, Client*> ClientMap;
297 ClientMap clients_;
298 STLValueDeleter<ClientMap> clients_deleter_;
300 // This is the current number of clients we know about that have
301 // cards. When this number matches alsa_card_midi_count_, we know
302 // we are in sync between ALSA and udev. Until then, we cannot generate
303 // MIDIConnectionEvents to web clients.
304 int card_client_count_;
306 DISALLOW_COPY_AND_ASSIGN(AlsaSeqState);
309 class AlsaCard {
310 public:
311 AlsaCard(udev_device* dev,
312 const std::string& name,
313 const std::string& longname,
314 const std::string& driver,
315 int midi_device_count);
316 ~AlsaCard();
317 std::string name() const { return name_; }
318 std::string longname() const { return longname_; }
319 std::string driver() const { return driver_; }
320 std::string path() const { return path_; }
321 std::string bus() const { return bus_; }
322 std::string vendor_id() const { return vendor_id_; }
323 std::string model_id() const { return model_id_; }
324 std::string usb_interface_num() const { return usb_interface_num_; }
325 std::string serial() const { return serial_; }
326 int midi_device_count() const { return midi_device_count_; }
327 std::string manufacturer() const { return manufacturer_; }
329 private:
330 FRIEND_TEST_ALL_PREFIXES(MidiManagerAlsaTest, ExtractManufacturer);
332 // Extracts the manufacturer using heuristics and a variety of sources.
333 static std::string ExtractManufacturerString(
334 const std::string& udev_id_vendor,
335 const std::string& udev_id_vendor_id,
336 const std::string& udev_id_vendor_from_database,
337 const std::string& name,
338 const std::string& longname);
340 const std::string name_;
341 const std::string longname_;
342 const std::string driver_;
343 const std::string path_;
344 const std::string bus_;
345 const std::string vendor_id_;
346 const std::string model_id_;
347 const std::string usb_interface_num_;
348 const std::string serial_;
349 const int midi_device_count_;
350 const std::string manufacturer_;
352 DISALLOW_COPY_AND_ASSIGN(AlsaCard);
355 typedef base::hash_map<int, uint32> SourceMap;
356 typedef base::hash_map<uint32, int> OutPortMap;
358 // An internal callback that runs on MidiSendThread.
359 void SendMidiData(uint32 port_index, const std::vector<uint8>& data);
361 void ScheduleEventLoop();
362 void EventLoop();
363 void ProcessSingleEvent(snd_seq_event_t* event, double timestamp);
364 void ProcessClientStartEvent(int client_id);
365 void ProcessPortStartEvent(const snd_seq_addr_t& addr);
366 void ProcessClientExitEvent(const snd_seq_addr_t& addr);
367 void ProcessPortExitEvent(const snd_seq_addr_t& addr);
368 void ProcessUdevEvent(udev_device* dev);
369 void AddCard(udev_device* dev);
370 void RemoveCard(int number);
372 // Updates port_state_ and Web MIDI state from alsa_seq_state_.
373 void UpdatePortStateAndGenerateEvents();
375 // Enumerates ports. Call once after subscribing to the announce port.
376 void EnumerateAlsaPorts();
377 // Enumerates udev cards. Call once after initializing the udev monitor.
378 bool EnumerateUdevCards();
379 // Returns true if successful.
380 bool CreateAlsaOutputPort(uint32 port_index, int client_id, int port_id);
381 void DeleteAlsaOutputPort(uint32 port_index);
382 // Returns true if successful.
383 bool Subscribe(uint32 port_index, int client_id, int port_id);
385 AlsaSeqState alsa_seq_state_;
386 MidiPortState port_state_;
388 // ALSA seq handles.
389 snd_seq_t* in_client_;
390 int in_client_id_;
391 snd_seq_t* out_client_;
392 int out_client_id_;
394 // One input port, many output ports.
395 int in_port_id_;
396 OutPortMap out_ports_; // guarded by out_ports_lock_
397 base::Lock out_ports_lock_; // guards out_ports_
399 // Mapping from ALSA client:port to our index.
400 SourceMap source_map_;
402 // Mapping from card to devices.
403 AlsaCardMap alsa_cards_;
404 STLValueDeleter<AlsaCardMap> alsa_cards_deleter_;
406 // This is the current count of midi devices across all cards we know
407 // about. When this number matches card_client_count_ in AlsaSeqState,
408 // we are safe to generate MIDIConnectionEvents. Otherwise we need to
409 // wait for our information from ALSA and udev to get back in sync.
410 int alsa_card_midi_count_;
412 // ALSA event -> MIDI coder.
413 snd_midi_event_t* decoder_;
415 // udev, for querying hardware devices.
416 device::ScopedUdevPtr udev_;
417 device::ScopedUdevMonitorPtr udev_monitor_;
419 base::Thread send_thread_;
420 base::Thread event_thread_;
422 bool event_thread_shutdown_; // guarded by shutdown_lock_
423 base::Lock shutdown_lock_; // guards event_thread_shutdown_
425 DISALLOW_COPY_AND_ASSIGN(MidiManagerAlsa);
428 } // namespace midi
429 } // namespace media
431 #endif // MEDIA_MIDI_MIDI_MANAGER_ALSA_H_