blob: 66f427acf3bc6383f9e3e58139014d0b93f74a1b [file] [log] [blame]
toyoshim@chromium.orga97eebf2014-01-03 07:52:39 +00001// 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.
4
dnicoara@chromium.org9f2a6f02014-01-03 21:25:00 +00005#ifndef MEDIA_MIDI_MIDI_MANAGER_ALSA_H_
6#define MEDIA_MIDI_MIDI_MANAGER_ALSA_H_
toyoshim@chromium.orga97eebf2014-01-03 07:52:39 +00007
agoode@chromium.org25227512014-06-08 05:12:05 +00008#include <alsa/asoundlib.h>
avi793390d2015-12-22 22:22:36 -08009#include <stdint.h>
danakj75afea02016-04-25 20:36:04 -070010
limasdfe59d0392015-11-19 20:28:57 -080011#include <map>
danakj75afea02016-04-25 20:36:04 -070012#include <memory>
dchengc2aeece2015-12-27 00:54:00 -080013#include <utility>
toyoshim@chromium.orga97eebf2014-01-03 07:52:39 +000014#include <vector>
15
bnc628660d2016-02-05 19:58:14 -080016#include "base/containers/hash_tables.h"
agoode55a8b522015-03-08 12:40:17 -070017#include "base/gtest_prod_util.h"
avieea95e82015-12-18 20:27:08 -080018#include "base/macros.h"
agoode@chromium.org25227512014-06-08 05:12:05 +000019#include "base/synchronization/lock.h"
toyoshim@chromium.orga97eebf2014-01-03 07:52:39 +000020#include "base/threading/thread.h"
agoodef212b2a2015-03-19 12:53:23 -070021#include "base/values.h"
agoode7de413f2015-04-24 00:13:39 -070022#include "device/udev_linux/scoped_udev.h"
brettw49ff0172015-05-05 12:43:04 -070023#include "media/midi/midi_export.h"
toyoshim@chromium.orga97eebf2014-01-03 07:52:39 +000024#include "media/midi/midi_manager.h"
25
agoodeb2ead822016-03-11 12:14:35 -080026namespace base {
27class ThreadChecker;
28}
29
toyoshim@chromium.orga97eebf2014-01-03 07:52:39 +000030namespace media {
toyoshime147c5e2015-05-07 21:58:31 -070031namespace midi {
toyoshim@chromium.orga97eebf2014-01-03 07:52:39 +000032
brettw49ff0172015-05-05 12:43:04 -070033class MIDI_EXPORT MidiManagerAlsa final : public MidiManager {
toyoshim@chromium.orga97eebf2014-01-03 07:52:39 +000034 public:
toyoshim@chromium.orgc82e66e2014-02-04 07:05:47 +000035 MidiManagerAlsa();
dcheng9e8524d2014-10-27 15:18:50 -070036 ~MidiManagerAlsa() override;
toyoshim@chromium.orga97eebf2014-01-03 07:52:39 +000037
toyoshim@chromium.orgc82e66e2014-02-04 07:05:47 +000038 // MidiManager implementation.
dcheng9e8524d2014-10-27 15:18:50 -070039 void StartInitialization() override;
toyoshim8e7d6e02015-10-06 08:47:17 -070040 void Finalize() override;
dcheng9e8524d2014-10-27 15:18:50 -070041 void DispatchSendMidiData(MidiManagerClient* client,
Avi Drissman3528fd02015-12-18 20:11:31 -050042 uint32_t port_index,
43 const std::vector<uint8_t>& data,
dcheng9e8524d2014-10-27 15:18:50 -070044 double timestamp) override;
toyoshim@chromium.orga97eebf2014-01-03 07:52:39 +000045
46 private:
agoode99d63292015-04-13 08:39:25 -070047 friend class MidiManagerAlsaTest;
agoode55a8b522015-03-08 12:40:17 -070048 FRIEND_TEST_ALL_PREFIXES(MidiManagerAlsaTest, ExtractManufacturer);
agoode99d63292015-04-13 08:39:25 -070049 FRIEND_TEST_ALL_PREFIXES(MidiManagerAlsaTest, ToMidiPortState);
agoode55a8b522015-03-08 12:40:17 -070050
agoodeb09423b2015-05-11 11:39:57 -070051 class AlsaCard;
danakj75afea02016-04-25 20:36:04 -070052 using AlsaCardMap = std::map<int, std::unique_ptr<AlsaCard>>;
agoodeb09423b2015-05-11 11:39:57 -070053
agoode99d63292015-04-13 08:39:25 -070054 class MidiPort {
agoodef212b2a2015-03-19 12:53:23 -070055 public:
56 enum class Type { kInput, kOutput };
57
agooded87fc0f2015-05-21 08:29:31 -070058 // The Id class is used to keep the multiple strings separate
59 // but compare them all together for equality purposes.
60 // The individual strings that make up the Id can theoretically contain
61 // arbitrary characters, so unfortunately there is no simple way to
62 // concatenate them into a single string.
63 class Id final {
64 public:
65 Id();
66 Id(const std::string& bus,
67 const std::string& vendor_id,
68 const std::string& model_id,
69 const std::string& usb_interface_num,
70 const std::string& serial);
71 Id(const Id&);
72 ~Id();
73 bool operator==(const Id&) const;
74 bool empty() const;
75
76 std::string bus() const { return bus_; }
77 std::string vendor_id() const { return vendor_id_; }
78 std::string model_id() const { return model_id_; }
79 std::string usb_interface_num() const { return usb_interface_num_; }
80 std::string serial() const { return serial_; }
81
82 private:
83 std::string bus_;
84 std::string vendor_id_;
85 std::string model_id_;
86 std::string usb_interface_num_;
87 std::string serial_;
88 };
89
agoode99d63292015-04-13 08:39:25 -070090 MidiPort(const std::string& path,
agooded87fc0f2015-05-21 08:29:31 -070091 const Id& id,
agoode99d63292015-04-13 08:39:25 -070092 int client_id,
93 int port_id,
94 int midi_device,
95 const std::string& client_name,
96 const std::string& port_name,
97 const std::string& manufacturer,
98 const std::string& version,
99 Type type);
100 ~MidiPort();
agoodef212b2a2015-03-19 12:53:23 -0700101
102 // Gets a Value representation of this object, suitable for serialization.
danakj75afea02016-04-25 20:36:04 -0700103 std::unique_ptr<base::Value> Value() const;
agoodef212b2a2015-03-19 12:53:23 -0700104
105 // Gets a string version of Value in JSON format.
106 std::string JSONValue() const;
107
108 // Gets an opaque identifier for this object, suitable for using as the id
109 // field in MidiPort.id on the web. Note that this string does not store
110 // the full state.
111 std::string OpaqueKey() const;
112
agoode99d63292015-04-13 08:39:25 -0700113 // Checks for equality for connected ports.
114 bool MatchConnected(const MidiPort& query) const;
115 // Checks for equality for kernel cards with id, pass 1.
116 bool MatchCardPass1(const MidiPort& query) const;
117 // Checks for equality for kernel cards with id, pass 2.
118 bool MatchCardPass2(const MidiPort& query) const;
119 // Checks for equality for non-card clients, pass 1.
120 bool MatchNoCardPass1(const MidiPort& query) const;
121 // Checks for equality for non-card clients, pass 2.
122 bool MatchNoCardPass2(const MidiPort& query) const;
agoodef212b2a2015-03-19 12:53:23 -0700123
agoode99d63292015-04-13 08:39:25 -0700124 // accessors
125 std::string path() const { return path_; }
agooded87fc0f2015-05-21 08:29:31 -0700126 Id id() const { return id_; }
agoode99d63292015-04-13 08:39:25 -0700127 std::string client_name() const { return client_name_; }
128 std::string port_name() const { return port_name_; }
129 std::string manufacturer() const { return manufacturer_; }
130 std::string version() const { return version_; }
131 int client_id() const { return client_id_; }
132 int port_id() const { return port_id_; }
133 int midi_device() const { return midi_device_; }
134 Type type() const { return type_; }
Avi Drissman3528fd02015-12-18 20:11:31 -0500135 uint32_t web_port_index() const { return web_port_index_; }
agoode99d63292015-04-13 08:39:25 -0700136 bool connected() const { return connected_; }
137
138 // mutators
Avi Drissman3528fd02015-12-18 20:11:31 -0500139 void set_web_port_index(uint32_t web_port_index) {
agoode99d63292015-04-13 08:39:25 -0700140 web_port_index_ = web_port_index;
141 }
142 void set_connected(bool connected) { connected_ = connected; }
143 void Update(const std::string& path,
144 int client_id,
145 int port_id,
146 const std::string& client_name,
147 const std::string& port_name,
148 const std::string& manufacturer,
149 const std::string& version) {
150 path_ = path;
151 client_id_ = client_id;
152 port_id_ = port_id;
153 client_name_ = client_name;
154 port_name_ = port_name;
155 manufacturer_ = manufacturer;
156 version_ = version;
157 }
158
159 private:
160 // Immutable properties.
agooded87fc0f2015-05-21 08:29:31 -0700161 const Id id_;
agoode99d63292015-04-13 08:39:25 -0700162 const int midi_device_;
163
agoodef212b2a2015-03-19 12:53:23 -0700164 const Type type_;
165
agoode99d63292015-04-13 08:39:25 -0700166 // Mutable properties. These will get updated as ports move around or
167 // drivers change.
168 std::string path_;
169 int client_id_;
170 int port_id_;
171 std::string client_name_;
172 std::string port_name_;
173 std::string manufacturer_;
174 std::string version_;
175
176 // Index for MidiManager.
Avi Drissman3528fd02015-12-18 20:11:31 -0500177 uint32_t web_port_index_ = 0;
agoode99d63292015-04-13 08:39:25 -0700178
179 // Port is present in the ALSA system.
agoode5a1aa112015-06-21 20:51:00 -0700180 bool connected_ = true;
agoode99d63292015-04-13 08:39:25 -0700181
182 DISALLOW_COPY_AND_ASSIGN(MidiPort);
agoode55a8b522015-03-08 12:40:17 -0700183 };
184
agoode99d63292015-04-13 08:39:25 -0700185 class MidiPortStateBase {
186 public:
danakj75afea02016-04-25 20:36:04 -0700187 typedef std::vector<std::unique_ptr<MidiPort>>::iterator iterator;
agoodebd4be9b2015-03-16 19:17:25 -0700188
agoode99d63292015-04-13 08:39:25 -0700189 virtual ~MidiPortStateBase();
190
191 // Given a port, finds a port in the internal store.
192 iterator Find(const MidiPort& port);
193
194 // Given a port, finds a connected port, using exact matching.
195 iterator FindConnected(const MidiPort& port);
196
197 // Given a port, finds a disconnected port, using heuristic matching.
198 iterator FindDisconnected(const MidiPort& port);
199
200 iterator begin() { return ports_.begin(); }
201 iterator end() { return ports_.end(); }
202
203 protected:
204 MidiPortStateBase();
agoode5ebc4932015-12-01 08:25:12 -0800205 iterator erase(iterator position) { return ports_.erase(position); }
danakj75afea02016-04-25 20:36:04 -0700206 void push_back(std::unique_ptr<MidiPort> port) {
dchengc2aeece2015-12-27 00:54:00 -0800207 ports_.push_back(std::move(port));
208 }
agoode99d63292015-04-13 08:39:25 -0700209
210 private:
danakj75afea02016-04-25 20:36:04 -0700211 std::vector<std::unique_ptr<MidiPort>> ports_;
agoode99d63292015-04-13 08:39:25 -0700212
213 DISALLOW_COPY_AND_ASSIGN(MidiPortStateBase);
214 };
215
216 class TemporaryMidiPortState final : public MidiPortStateBase {
217 public:
agoode5ebc4932015-12-01 08:25:12 -0800218 iterator erase(iterator position) {
219 return MidiPortStateBase::erase(position);
220 };
danakj75afea02016-04-25 20:36:04 -0700221 void push_back(std::unique_ptr<MidiPort> port) {
dchengc2aeece2015-12-27 00:54:00 -0800222 MidiPortStateBase::push_back(std::move(port));
agoode5ebc4932015-12-01 08:25:12 -0800223 }
agoode99d63292015-04-13 08:39:25 -0700224 };
225
226 class MidiPortState final : public MidiPortStateBase {
227 public:
228 MidiPortState();
229
agoode5ebc4932015-12-01 08:25:12 -0800230 // Inserts a port at the end. Returns web_port_index.
danakj75afea02016-04-25 20:36:04 -0700231 uint32_t push_back(std::unique_ptr<MidiPort> port);
agoode99d63292015-04-13 08:39:25 -0700232
233 private:
Avi Drissman3528fd02015-12-18 20:11:31 -0500234 uint32_t num_input_ports_ = 0;
235 uint32_t num_output_ports_ = 0;
agoode99d63292015-04-13 08:39:25 -0700236 };
237
238 class AlsaSeqState {
239 public:
240 enum class PortDirection { kInput, kOutput, kDuplex };
241
242 AlsaSeqState();
243 ~AlsaSeqState();
244
245 void ClientStart(int client_id,
246 const std::string& client_name,
247 snd_seq_client_type_t type);
248 bool ClientStarted(int client_id);
249 void ClientExit(int client_id);
250 void PortStart(int client_id,
251 int port_id,
252 const std::string& port_name,
253 PortDirection direction,
254 bool midi);
255 void PortExit(int client_id, int port_id);
256 snd_seq_client_type_t ClientType(int client_id) const;
danakj75afea02016-04-25 20:36:04 -0700257 std::unique_ptr<TemporaryMidiPortState> ToMidiPortState(
agoodeb09423b2015-05-11 11:39:57 -0700258 const AlsaCardMap& alsa_cards);
259
260 int card_client_count() { return card_client_count_; }
agoode99d63292015-04-13 08:39:25 -0700261
262 private:
263 class Port {
264 public:
265 Port(const std::string& name, PortDirection direction, bool midi);
266 ~Port();
267
agoodeb0582872015-05-20 05:22:24 -0700268 std::string name() const { return name_; }
269 PortDirection direction() const { return direction_; }
agoode99d63292015-04-13 08:39:25 -0700270 // True if this port is a MIDI port, instead of another kind of ALSA port.
agoodeb0582872015-05-20 05:22:24 -0700271 bool midi() const { return midi_; }
agoode99d63292015-04-13 08:39:25 -0700272
273 private:
274 const std::string name_;
275 const PortDirection direction_;
276 const bool midi_;
277
278 DISALLOW_COPY_AND_ASSIGN(Port);
279 };
280
281 class Client {
282 public:
danakj75afea02016-04-25 20:36:04 -0700283 using PortMap = std::map<int, std::unique_ptr<Port>>;
agoode99d63292015-04-13 08:39:25 -0700284
285 Client(const std::string& name, snd_seq_client_type_t type);
286 ~Client();
287
agoodeb0582872015-05-20 05:22:24 -0700288 std::string name() const { return name_; }
289 snd_seq_client_type_t type() const { return type_; }
danakj75afea02016-04-25 20:36:04 -0700290 void AddPort(int addr, std::unique_ptr<Port> port);
agoode99d63292015-04-13 08:39:25 -0700291 void RemovePort(int addr);
292 PortMap::const_iterator begin() const;
293 PortMap::const_iterator end() const;
294
295 private:
296 const std::string name_;
297 const snd_seq_client_type_t type_;
298 PortMap ports_;
agoode99d63292015-04-13 08:39:25 -0700299
300 DISALLOW_COPY_AND_ASSIGN(Client);
301 };
302
danakj75afea02016-04-25 20:36:04 -0700303 std::map<int, std::unique_ptr<Client>> clients_;
agoode99d63292015-04-13 08:39:25 -0700304
agoodeb09423b2015-05-11 11:39:57 -0700305 // This is the current number of clients we know about that have
306 // cards. When this number matches alsa_card_midi_count_, we know
307 // we are in sync between ALSA and udev. Until then, we cannot generate
308 // MIDIConnectionEvents to web clients.
agoodedf1b9ff2015-06-25 18:14:50 -0700309 int card_client_count_ = 0;
agoodeb09423b2015-05-11 11:39:57 -0700310
agoode99d63292015-04-13 08:39:25 -0700311 DISALLOW_COPY_AND_ASSIGN(AlsaSeqState);
312 };
313
agoodeb09423b2015-05-11 11:39:57 -0700314 class AlsaCard {
315 public:
316 AlsaCard(udev_device* dev,
agooded87fc0f2015-05-21 08:29:31 -0700317 const std::string& name,
318 const std::string& longname,
319 const std::string& driver,
agoodeb09423b2015-05-11 11:39:57 -0700320 int midi_device_count);
321 ~AlsaCard();
agooded87fc0f2015-05-21 08:29:31 -0700322 std::string name() const { return name_; }
323 std::string longname() const { return longname_; }
324 std::string driver() const { return driver_; }
325 std::string path() const { return path_; }
326 std::string bus() const { return bus_; }
327 std::string vendor_id() const { return vendor_id_; }
328 std::string model_id() const { return model_id_; }
329 std::string usb_interface_num() const { return usb_interface_num_; }
330 std::string serial() const { return serial_; }
agoodeb09423b2015-05-11 11:39:57 -0700331 int midi_device_count() const { return midi_device_count_; }
agooded87fc0f2015-05-21 08:29:31 -0700332 std::string manufacturer() const { return manufacturer_; }
agoodeb09423b2015-05-11 11:39:57 -0700333
334 private:
335 FRIEND_TEST_ALL_PREFIXES(MidiManagerAlsaTest, ExtractManufacturer);
336
337 // Extracts the manufacturer using heuristics and a variety of sources.
338 static std::string ExtractManufacturerString(
339 const std::string& udev_id_vendor,
340 const std::string& udev_id_vendor_id,
341 const std::string& udev_id_vendor_from_database,
agooded87fc0f2015-05-21 08:29:31 -0700342 const std::string& name,
343 const std::string& longname);
agoodeb09423b2015-05-11 11:39:57 -0700344
agooded87fc0f2015-05-21 08:29:31 -0700345 const std::string name_;
346 const std::string longname_;
347 const std::string driver_;
348 const std::string path_;
349 const std::string bus_;
350 const std::string vendor_id_;
351 const std::string model_id_;
352 const std::string usb_interface_num_;
353 const std::string serial_;
354 const int midi_device_count_;
355 const std::string manufacturer_;
agoodeb09423b2015-05-11 11:39:57 -0700356
357 DISALLOW_COPY_AND_ASSIGN(AlsaCard);
358 };
359
agoode5a1aa112015-06-21 20:51:00 -0700360 struct SndSeqDeleter {
361 void operator()(snd_seq_t* seq) const { snd_seq_close(seq); }
362 };
363
364 struct SndMidiEventDeleter {
365 void operator()(snd_midi_event_t* coder) const {
366 snd_midi_event_free(coder);
367 };
368 };
369
agoodeb2ead822016-03-11 12:14:35 -0800370 using SourceMap = base::hash_map<int, uint32_t>;
371 using OutPortMap = base::hash_map<uint32_t, int>;
danakj75afea02016-04-25 20:36:04 -0700372 using ScopedSndSeqPtr = std::unique_ptr<snd_seq_t, SndSeqDeleter>;
agoodeb2ead822016-03-11 12:14:35 -0800373 using ScopedSndMidiEventPtr =
danakj75afea02016-04-25 20:36:04 -0700374 std::unique_ptr<snd_midi_event_t, SndMidiEventDeleter>;
agoode99d63292015-04-13 08:39:25 -0700375
agoode@chromium.org25227512014-06-08 05:12:05 +0000376 // An internal callback that runs on MidiSendThread.
Avi Drissman3528fd02015-12-18 20:11:31 -0500377 void SendMidiData(uint32_t port_index, const std::vector<uint8_t>& data);
agoode@chromium.org25227512014-06-08 05:12:05 +0000378
agoodebd4be9b2015-03-16 19:17:25 -0700379 void ScheduleEventLoop();
toyoshim@chromium.org4a8657c2014-02-06 11:23:09 +0000380 void EventLoop();
agoodebd4be9b2015-03-16 19:17:25 -0700381 void ProcessSingleEvent(snd_seq_event_t* event, double timestamp);
agoode99d63292015-04-13 08:39:25 -0700382 void ProcessClientStartEvent(int client_id);
383 void ProcessPortStartEvent(const snd_seq_addr_t& addr);
384 void ProcessClientExitEvent(const snd_seq_addr_t& addr);
385 void ProcessPortExitEvent(const snd_seq_addr_t& addr);
agoode975043d2015-05-11 00:46:17 -0700386 void ProcessUdevEvent(udev_device* dev);
agoodeb09423b2015-05-11 11:39:57 -0700387 void AddCard(udev_device* dev);
388 void RemoveCard(int number);
agoode99d63292015-04-13 08:39:25 -0700389
390 // Updates port_state_ and Web MIDI state from alsa_seq_state_.
391 void UpdatePortStateAndGenerateEvents();
392
393 // Enumerates ports. Call once after subscribing to the announce port.
394 void EnumerateAlsaPorts();
agoode975043d2015-05-11 00:46:17 -0700395 // Enumerates udev cards. Call once after initializing the udev monitor.
396 bool EnumerateUdevCards();
agoode99d63292015-04-13 08:39:25 -0700397 // Returns true if successful.
Avi Drissman3528fd02015-12-18 20:11:31 -0500398 bool CreateAlsaOutputPort(uint32_t port_index, int client_id, int port_id);
399 void DeleteAlsaOutputPort(uint32_t port_index);
agoode99d63292015-04-13 08:39:25 -0700400 // Returns true if successful.
Avi Drissman3528fd02015-12-18 20:11:31 -0500401 bool Subscribe(uint32_t port_index, int client_id, int port_id);
agoode99d63292015-04-13 08:39:25 -0700402
agoodeb2ead822016-03-11 12:14:35 -0800403 // Members initialized in the constructor are below.
404 // Our copies of the internal state of the ports of seq and udev.
agoode99d63292015-04-13 08:39:25 -0700405 AlsaSeqState alsa_seq_state_;
406 MidiPortState port_state_;
toyoshim@chromium.org4a8657c2014-02-06 11:23:09 +0000407
agoode@chromium.org25227512014-06-08 05:12:05 +0000408 // One input port, many output ports.
agoode99d63292015-04-13 08:39:25 -0700409 base::Lock out_ports_lock_; // guards out_ports_
agoodeb2ead822016-03-11 12:14:35 -0800410 OutPortMap out_ports_; // guarded by out_ports_lock_
agoode@chromium.org25227512014-06-08 05:12:05 +0000411
agoodebd4be9b2015-03-16 19:17:25 -0700412 // Mapping from ALSA client:port to our index.
agoode@chromium.org25227512014-06-08 05:12:05 +0000413 SourceMap source_map_;
414
agoodeb09423b2015-05-11 11:39:57 -0700415 // Mapping from card to devices.
416 AlsaCardMap alsa_cards_;
agoodeb09423b2015-05-11 11:39:57 -0700417
418 // This is the current count of midi devices across all cards we know
419 // about. When this number matches card_client_count_ in AlsaSeqState,
420 // we are safe to generate MIDIConnectionEvents. Otherwise we need to
421 // wait for our information from ALSA and udev to get back in sync.
agoode5a1aa112015-06-21 20:51:00 -0700422 int alsa_card_midi_count_ = 0;
agoodeb09423b2015-05-11 11:39:57 -0700423
agoodeb2ead822016-03-11 12:14:35 -0800424 base::Lock shutdown_lock_; // guards event_thread_shutdown_
425 bool event_thread_shutdown_ = false; // guarded by shutdown_lock_
426
427 // This lock is needed to ensure that members destroyed in Finalize
428 // will be visibly destroyed before the destructor is run in the
429 // other thread. Otherwise, the same objects may have their destructors
430 // run multiple times in different threads.
431 base::Lock lazy_init_member_lock_; // guards members below
432
433 // Members initialized in StartInitialization() are below.
434 // Make sure to destroy these in Finalize()!
danakj75afea02016-04-25 20:36:04 -0700435 std::unique_ptr<base::ThreadChecker> initialization_thread_checker_;
agoodeb2ead822016-03-11 12:14:35 -0800436
437 // ALSA seq handles and ids.
438 ScopedSndSeqPtr in_client_;
439 int in_client_id_;
440 ScopedSndSeqPtr out_client_;
441 int out_client_id_;
442 int in_port_id_;
443
agoode99d63292015-04-13 08:39:25 -0700444 // ALSA event -> MIDI coder.
agoodeb2ead822016-03-11 12:14:35 -0800445 ScopedSndMidiEventPtr decoder_;
agoode@chromium.org25227512014-06-08 05:12:05 +0000446
agoode7de413f2015-04-24 00:13:39 -0700447 // udev, for querying hardware devices.
448 device::ScopedUdevPtr udev_;
agoode975043d2015-05-11 00:46:17 -0700449 device::ScopedUdevMonitorPtr udev_monitor_;
agoode7de413f2015-04-24 00:13:39 -0700450
agoodeb2ead822016-03-11 12:14:35 -0800451 // Threads for sending and receiving. These are initialized in the
452 // constructor, but are started at the end of StartInitialization.
toyoshim@chromium.org4a8657c2014-02-06 11:23:09 +0000453 base::Thread event_thread_;
agoodeb2ead822016-03-11 12:14:35 -0800454 base::Thread send_thread_;
toyoshim@chromium.org4a8657c2014-02-06 11:23:09 +0000455
toyoshim@chromium.orgc82e66e2014-02-04 07:05:47 +0000456 DISALLOW_COPY_AND_ASSIGN(MidiManagerAlsa);
toyoshim@chromium.orga97eebf2014-01-03 07:52:39 +0000457};
458
toyoshime147c5e2015-05-07 21:58:31 -0700459} // namespace midi
toyoshim@chromium.orga97eebf2014-01-03 07:52:39 +0000460} // namespace media
461
dnicoara@chromium.org9f2a6f02014-01-03 21:25:00 +0000462#endif // MEDIA_MIDI_MIDI_MANAGER_ALSA_H_