Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(480)

Side by Side Diff: media/midi/midi_manager_alsa.cc

Issue 1020783002: Web MIDI (Linux): Improve id quality, create opaque id, prep for hotplug (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Put note about SHA256 and use OpaqueKey for now Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « media/midi/midi_manager_alsa.h ('k') | media/midi/midi_manager_alsa_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "media/midi/midi_manager_alsa.h" 5 #include "media/midi/midi_manager_alsa.h"
6 6
7 #include <alsa/asoundlib.h> 7 #include <alsa/asoundlib.h>
8 #include <stdlib.h> 8 #include <stdlib.h>
9 #include <algorithm> 9 #include <algorithm>
10 #include <string> 10 #include <string>
11 11
12 #include "base/bind.h" 12 #include "base/bind.h"
13 #include "base/json/json_string_value_serializer.h"
13 #include "base/logging.h" 14 #include "base/logging.h"
14 #include "base/memory/ref_counted.h" 15 #include "base/memory/scoped_ptr.h"
15 #include "base/memory/scoped_vector.h" 16 #include "base/memory/scoped_vector.h"
16 #include "base/message_loop/message_loop.h" 17 #include "base/message_loop/message_loop.h"
17 #include "base/posix/eintr_wrapper.h" 18 #include "base/posix/eintr_wrapper.h"
19 #include "base/strings/string_number_conversions.h"
18 #include "base/strings/stringprintf.h" 20 #include "base/strings/stringprintf.h"
19 #include "base/threading/thread.h" 21 #include "base/threading/thread.h"
20 #include "base/time/time.h" 22 #include "base/time/time.h"
23 #include "base/values.h"
24 #include "crypto/sha2.h"
21 #include "media/midi/midi_port_info.h" 25 #include "media/midi/midi_port_info.h"
22 26
23 namespace media { 27 namespace media {
24 28
25 namespace { 29 namespace {
26 30
27 // Per-output buffer. This can be smaller, but then large sysex messages 31 // Per-output buffer. This can be smaller, but then large sysex messages
28 // will be (harmlessly) split across multiple seq events. This should 32 // will be (harmlessly) split across multiple seq events. This should
29 // not have any real practical effect, except perhaps to slightly reorder 33 // not have any real practical effect, except perhaps to slightly reorder
30 // realtime messages with respect to sysex. 34 // realtime messages with respect to sysex.
31 const size_t kSendBufferSize = 256; 35 const size_t kSendBufferSize = 256;
32 36
33 // Minimum client id for which we will have ALSA card devices for. When we 37 // Minimum client id for which we will have ALSA card devices for. When we
34 // are searching for card devices (used to get the path, id, and manufacturer), 38 // are searching for card devices (used to get the path, id, and manufacturer),
35 // we don't want to get confused by kernel clients that do not have a card. 39 // we don't want to get confused by kernel clients that do not have a card.
36 // See seq_clientmgr.c in the ALSA code for this. 40 // See seq_clientmgr.c in the ALSA code for this.
37 // TODO(agoode): Add proper client -> card export from the kernel to avoid 41 // TODO(agoode): Add proper client -> card export from the kernel to avoid
38 // hardcoding. 42 // hardcoding.
39 const int kMinimumClientIdForCards = 16; 43 const int kMinimumClientIdForCards = 16;
40 44
45 // udev key constants.
46 const char kSoundClass[] = "sound";
47 const char kIdVendor[] = "ID_VENDOR";
48 const char kIdVendorEnc[] = "ID_VENDOR_ENC";
49 const char kIdVendorFromDatabase[] = "ID_VENDOR_FROM_DATABASE";
50 const char kSysattrVendorName[] = "vendor_name";
51 const char kIdVendorId[] = "ID_VENDOR_ID";
52 const char kSysattrVendor[] = "vendor";
53 const char kIdModelId[] = "ID_MODEL_ID";
54 const char kSysattrModel[] = "model";
55 const char kIdBus[] = "ID_BUS";
56 const char kIdPath[] = "ID_PATH";
57 const char kUsbInterfaceNum[] = "ID_USB_INTERFACE_NUM";
58
59 // ALSA constants.
60 const char kAlsaHw[] = "hw";
61
41 // Constants for the capabilities we search for in inputs and outputs. 62 // Constants for the capabilities we search for in inputs and outputs.
42 // See http://www.alsa-project.org/alsa-doc/alsa-lib/seq.html. 63 // See http://www.alsa-project.org/alsa-doc/alsa-lib/seq.html.
43 const unsigned int kRequiredInputPortCaps = 64 const unsigned int kRequiredInputPortCaps =
44 SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_READ; 65 SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_READ;
45 const unsigned int kRequiredOutputPortCaps = 66 const unsigned int kRequiredOutputPortCaps =
46 SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE; 67 SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE;
47 68
48 int AddrToInt(const snd_seq_addr_t* addr) { 69 int AddrToInt(const snd_seq_addr_t* addr) {
49 return (addr->client << 8) | addr->port; 70 return (addr->client << 8) | addr->port;
50 } 71 }
51 72
73 // TODO(agoode): Move this to device/udev_linux.
74 #if defined(USE_UDEV)
75 const std::string UdevDeviceGetPropertyOrSysattr(
76 struct udev_device* udev_device,
77 const char* property_key,
78 const char* sysattr_key) {
79 // First try the property.
80 std::string value =
81 device::UdevDeviceGetPropertyValue(udev_device, property_key);
82
83 // If no property, look for sysattrs and walk up the parent devices too.
84 while (value.empty() && udev_device) {
85 value = device::UdevDeviceGetSysattrValue(udev_device, sysattr_key);
86 udev_device = device::udev_device_get_parent(udev_device);
87 }
88 return value;
89 }
90 #endif // defined(USE_UDEV)
91
52 } // namespace 92 } // namespace
53 93
54 MidiManagerAlsa::MidiManagerAlsa() 94 MidiManagerAlsa::MidiManagerAlsa()
55 : in_client_(NULL), 95 : in_client_(NULL),
56 out_client_(NULL), 96 out_client_(NULL),
57 out_client_id_(-1), 97 out_client_id_(-1),
58 in_port_(-1), 98 in_port_(-1),
59 decoder_(NULL), 99 decoder_(NULL),
60 #if defined(USE_UDEV) 100 #if defined(USE_UDEV)
61 udev_(device::udev_new()), 101 udev_(device::udev_new()),
(...skipping 25 matching lines...) Expand all
87 127
88 // Wait for the event thread to stop. 128 // Wait for the event thread to stop.
89 event_thread_.Stop(); 129 event_thread_.Stop();
90 130
91 // Close the in client. 131 // Close the in client.
92 if (in_client_) 132 if (in_client_)
93 snd_seq_close(in_client_); 133 snd_seq_close(in_client_);
94 134
95 // Free the decoder. 135 // Free the decoder.
96 snd_midi_event_free(decoder_); 136 snd_midi_event_free(decoder_);
97
98 // Free the encoders.
99 for (EncoderList::iterator i = encoders_.begin(); i != encoders_.end(); ++i)
100 snd_midi_event_free(*i);
101 } 137 }
102 138
103 void MidiManagerAlsa::StartInitialization() { 139 void MidiManagerAlsa::StartInitialization() {
104 // TODO(agoode): Move off I/O thread. See http://crbug.com/374341. 140 // TODO(agoode): Move off I/O thread. See http://crbug.com/374341.
105 141
106 // Create client handles. 142 // Create client handles.
107 int err = snd_seq_open(&in_client_, "hw", SND_SEQ_OPEN_INPUT, 0); 143 int err = snd_seq_open(&in_client_, kAlsaHw, SND_SEQ_OPEN_INPUT, 0);
108 if (err != 0) { 144 if (err != 0) {
109 VLOG(1) << "snd_seq_open fails: " << snd_strerror(err); 145 VLOG(1) << "snd_seq_open fails: " << snd_strerror(err);
110 return CompleteInitialization(MIDI_INITIALIZATION_ERROR); 146 return CompleteInitialization(MIDI_INITIALIZATION_ERROR);
111 } 147 }
112 int in_client_id = snd_seq_client_id(in_client_); 148 int in_client_id = snd_seq_client_id(in_client_);
113 err = snd_seq_open(&out_client_, "hw", SND_SEQ_OPEN_OUTPUT, 0); 149 err = snd_seq_open(&out_client_, kAlsaHw, SND_SEQ_OPEN_OUTPUT, 0);
114 if (err != 0) { 150 if (err != 0) {
115 VLOG(1) << "snd_seq_open fails: " << snd_strerror(err); 151 VLOG(1) << "snd_seq_open fails: " << snd_strerror(err);
116 return CompleteInitialization(MIDI_INITIALIZATION_ERROR); 152 return CompleteInitialization(MIDI_INITIALIZATION_ERROR);
117 } 153 }
118 out_client_id_ = snd_seq_client_id(out_client_); 154 out_client_id_ = snd_seq_client_id(out_client_);
119 155
120 // Name the clients. 156 // Name the clients.
121 err = snd_seq_set_client_name(in_client_, "Chrome (input)"); 157 err = snd_seq_set_client_name(in_client_, "Chrome (input)");
122 if (err != 0) { 158 if (err != 0) {
123 VLOG(1) << "snd_seq_set_client_name fails: " << snd_strerror(err); 159 VLOG(1) << "snd_seq_set_client_name fails: " << snd_strerror(err);
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
191 FROM_HERE, base::Bind(&MidiManagerAlsa::SendMidiData, 227 FROM_HERE, base::Bind(&MidiManagerAlsa::SendMidiData,
192 base::Unretained(this), port_index, data), 228 base::Unretained(this), port_index, data),
193 delay); 229 delay);
194 230
195 // Acknowledge send. 231 // Acknowledge send.
196 send_thread_.message_loop()->PostTask( 232 send_thread_.message_loop()->PostTask(
197 FROM_HERE, base::Bind(&MidiManagerClient::AccumulateMidiBytesSent, 233 FROM_HERE, base::Bind(&MidiManagerClient::AccumulateMidiBytesSent,
198 base::Unretained(client), data.size())); 234 base::Unretained(client), data.size()));
199 } 235 }
200 236
201 MidiManagerAlsa::MidiDevice::MidiDevice(const MidiManagerAlsa* outer, 237 MidiManagerAlsa::AlsaRawmidi::AlsaRawmidi(const MidiManagerAlsa* outer,
202 const std::string& alsa_name, 238 const std::string& alsa_name,
203 const std::string& alsa_longname, 239 const std::string& alsa_longname,
204 const std::string& alsa_driver, 240 const std::string& alsa_driver,
205 int card_index) 241 int card_index)
206 : alsa_name_(alsa_name), alsa_driver_(alsa_driver) { 242 : alsa_name_(alsa_name),
243 alsa_longname_(alsa_longname),
244 alsa_driver_(alsa_driver) {
207 // Get udev properties if available. 245 // Get udev properties if available.
208 std::string udev_id_vendor; 246 std::string vendor;
209 std::string udev_id_vendor_id; 247 std::string vendor_from_database;
210 std::string udev_id_vendor_from_database;
211 248
212 #if defined(USE_UDEV) 249 #if defined(USE_UDEV)
213 const std::string sysname = base::StringPrintf("card%i", card_index); 250 const std::string sysname = base::StringPrintf("card%i", card_index);
214 device::ScopedUdevDevicePtr udev_device( 251 device::ScopedUdevDevicePtr udev_device(
215 device::udev_device_new_from_subsystem_sysname(outer->udev_.get(), 252 device::udev_device_new_from_subsystem_sysname(
216 "sound", sysname.c_str())); 253 outer->udev_.get(), kSoundClass, sysname.c_str()));
217 udev_id_vendor = device::UdevDecodeString(
218 device::UdevDeviceGetPropertyValue(udev_device.get(), "ID_VENDOR_ENC"));
219 udev_id_vendor_id =
220 device::UdevDeviceGetPropertyValue(udev_device.get(), "ID_VENDOR_ID");
221 udev_id_vendor_from_database = device::UdevDeviceGetPropertyValue(
222 udev_device.get(), "ID_VENDOR_FROM_DATABASE");
223 254
224 udev_id_path_ = 255 // TODO(agoode): Move this to a new utility class in device/udev_linux?
225 device::UdevDeviceGetPropertyValue(udev_device.get(), "ID_PATH"); 256
226 udev_id_id_ = device::UdevDeviceGetPropertyValue(udev_device.get(), "ID_ID"); 257 // Try to get the vendor string. Sometimes it is encoded.
258 vendor = device::UdevDecodeString(
259 device::UdevDeviceGetPropertyValue(udev_device.get(), kIdVendorEnc));
260 // Sometimes it is not encoded.
261 if (vendor.empty())
262 UdevDeviceGetPropertyOrSysattr(udev_device.get(), kIdVendor,
263 kSysattrVendorName);
264 // Also get the vendor string from the hardware database.
265 vendor_from_database = device::UdevDeviceGetPropertyValue(
266 udev_device.get(), kIdVendorFromDatabase);
267
268 // Get the device path.
269 path_ = device::UdevDeviceGetPropertyValue(udev_device.get(), kIdPath);
270
271 // Get the bus.
272 bus_ = device::UdevDeviceGetPropertyValue(udev_device.get(), kIdBus);
273
274 // Get the vendor id, by either property or sysattr.
275 vendor_id_ = UdevDeviceGetPropertyOrSysattr(udev_device.get(), kIdVendorId,
276 kSysattrVendor);
277
278 // Get the model id, by either property or sysattr.
279 model_id_ = UdevDeviceGetPropertyOrSysattr(udev_device.get(), kIdModelId,
280 kSysattrModel);
281
282 // Get the usb interface number.
283 usb_interface_num_ =
284 device::UdevDeviceGetPropertyValue(udev_device.get(), kUsbInterfaceNum);
227 #endif // defined(USE_UDEV) 285 #endif // defined(USE_UDEV)
228 286
229 manufacturer_ = ExtractManufacturerString(udev_id_vendor, udev_id_vendor_id, 287 manufacturer_ = ExtractManufacturerString(
230 udev_id_vendor_from_database, 288 vendor, vendor_id_, vendor_from_database, alsa_name, alsa_longname);
231 alsa_name, alsa_longname);
232 } 289 }
233 290
234 MidiManagerAlsa::MidiDevice::~MidiDevice() { 291 MidiManagerAlsa::AlsaRawmidi::~AlsaRawmidi() {
235 } 292 }
236 293
237 const std::string MidiManagerAlsa::MidiDevice::alsa_name() const { 294 const std::string MidiManagerAlsa::AlsaRawmidi::alsa_name() const {
238 return alsa_name_; 295 return alsa_name_;
239 } 296 }
240 297
241 const std::string MidiManagerAlsa::MidiDevice::manufacturer() const { 298 const std::string MidiManagerAlsa::AlsaRawmidi::alsa_longname() const {
299 return alsa_longname_;
300 }
301
302 const std::string MidiManagerAlsa::AlsaRawmidi::manufacturer() const {
242 return manufacturer_; 303 return manufacturer_;
243 } 304 }
244 305
245 const std::string MidiManagerAlsa::MidiDevice::alsa_driver() const { 306 const std::string MidiManagerAlsa::AlsaRawmidi::alsa_driver() const {
246 return alsa_driver_; 307 return alsa_driver_;
247 } 308 }
248 309
249 const std::string MidiManagerAlsa::MidiDevice::udev_id_path() const { 310 const std::string MidiManagerAlsa::AlsaRawmidi::path() const {
250 return udev_id_path_; 311 return path_;
251 } 312 }
252 313
253 const std::string MidiManagerAlsa::MidiDevice::udev_id_id() const { 314 const std::string MidiManagerAlsa::AlsaRawmidi::bus() const {
254 return udev_id_id_; 315 return bus_;
316 }
317
318 const std::string MidiManagerAlsa::AlsaRawmidi::vendor_id() const {
319 return vendor_id_;
320 }
321
322 const std::string MidiManagerAlsa::AlsaRawmidi::id() const {
323 std::string id = vendor_id_;
324 if (!model_id_.empty())
325 id += ":" + model_id_;
326 if (!usb_interface_num_.empty())
327 id += ":" + usb_interface_num_;
328 return id;
255 } 329 }
256 330
257 // static 331 // static
258 std::string MidiManagerAlsa::MidiDevice::ExtractManufacturerString( 332 std::string MidiManagerAlsa::AlsaRawmidi::ExtractManufacturerString(
259 const std::string& udev_id_vendor, 333 const std::string& udev_id_vendor,
260 const std::string& udev_id_vendor_id, 334 const std::string& udev_id_vendor_id,
261 const std::string& udev_id_vendor_from_database, 335 const std::string& udev_id_vendor_from_database,
262 const std::string& alsa_name, 336 const std::string& alsa_name,
263 const std::string& alsa_longname) { 337 const std::string& alsa_longname) {
264 // Let's try to determine the manufacturer. Here is the ordered preference 338 // Let's try to determine the manufacturer. Here is the ordered preference
265 // in extraction: 339 // in extraction:
266 // 1. Vendor name from the USB device iManufacturer string, from 340 // 1. Vendor name from the hardware device string, from udev properties
267 // the udev property ID_VENDOR_ENC. 341 // or sysattrs.
268 // 2. Vendor name from the udev database (property ID_VENDOR_FROM_DATABASE). 342 // 2. Vendor name from the udev database (property ID_VENDOR_FROM_DATABASE).
269 // 3. Heuristic from ALSA. 343 // 3. Heuristic from ALSA.
270 344
271 // Is the vendor string not just the USB vendor hex id? 345 // Is the vendor string not just the vendor hex id?
272 if (udev_id_vendor != udev_id_vendor_id) { 346 if (udev_id_vendor != udev_id_vendor_id) {
273 return udev_id_vendor; 347 return udev_id_vendor;
274 } 348 }
275 349
276 // Is there a vendor string in the hardware database? 350 // Is there a vendor string in the hardware database?
277 if (!udev_id_vendor_from_database.empty()) { 351 if (!udev_id_vendor_from_database.empty()) {
278 return udev_id_vendor_from_database; 352 return udev_id_vendor_from_database;
279 } 353 }
280 354
281 // Ok, udev gave us nothing useful, or was unavailable. So try a heuristic. 355 // Ok, udev gave us nothing useful, or was unavailable. So try a heuristic.
282 // We assume that card longname is in the format of 356 // We assume that card longname is in the format of
283 // "<manufacturer> <name> at <bus>". Otherwise, we give up to detect 357 // "<manufacturer> <name> at <bus>". Otherwise, we give up to detect
284 // a manufacturer name here. 358 // a manufacturer name here.
285 size_t at_index = alsa_longname.rfind(" at "); 359 size_t at_index = alsa_longname.rfind(" at ");
286 if (std::string::npos != at_index) { 360 if (at_index && at_index != std::string::npos) {
287 size_t name_index = alsa_longname.rfind(alsa_name, at_index - 1); 361 size_t name_index = alsa_longname.rfind(alsa_name, at_index - 1);
288 if (std::string::npos != name_index) 362 if (name_index && name_index != std::string::npos)
289 return alsa_longname.substr(0, name_index - 1); 363 return alsa_longname.substr(0, name_index - 1);
290 } 364 }
291 365
292 // Failure. 366 // Failure.
293 return ""; 367 return "";
294 } 368 }
295 369
296 ScopedVector<MidiManagerAlsa::MidiDevice> MidiManagerAlsa::AllMidiDevices() { 370 MidiManagerAlsa::AlsaPortMetadata::AlsaPortMetadata(
297 ScopedVector<MidiDevice> devices; 371 const std::string& path,
372 const std::string& bus,
373 const std::string& id,
374 const snd_seq_addr_t* address,
375 const std::string& client_name,
376 const std::string& port_name,
377 const std::string& card_name,
378 const std::string& card_longname,
379 Type type)
380 : path_(path),
381 bus_(bus),
382 id_(id),
383 client_addr_(address->client),
384 port_addr_(address->port),
385 client_name_(client_name),
386 port_name_(port_name),
387 card_name_(card_name),
388 card_longname_(card_longname),
389 type_(type) {
390 }
391
392 MidiManagerAlsa::AlsaPortMetadata::~AlsaPortMetadata() {
393 }
394
395 scoped_ptr<base::Value> MidiManagerAlsa::AlsaPortMetadata::Value() const {
396 base::DictionaryValue* value = new base::DictionaryValue();
397 value->SetString("path", path_);
398 value->SetString("bus", bus_);
399 value->SetString("id", id_);
400 value->SetInteger("clientAddr", client_addr_);
401 value->SetInteger("portAddr", port_addr_);
402 value->SetString("clientName", client_name_);
403 value->SetString("portName", port_name_);
404 value->SetString("cardName", card_name_);
405 value->SetString("cardLongname", card_longname_);
406 std::string type;
407 switch (type_) {
408 case Type::kInput:
409 type = "input";
410 break;
411
412 case Type::kOutput:
413 type = "output";
414 break;
415 }
416 value->SetString("type", type);
417
418 return scoped_ptr<base::Value>(value).Pass();
419 }
420
421 std::string MidiManagerAlsa::AlsaPortMetadata::JSONValue() const {
422 std::string json;
423 JSONStringValueSerializer serializer(&json);
424 serializer.Serialize(*Value().get());
425 return json;
426 }
427
428 // TODO(agoode): Do not use SHA256 here. Instead store a persistent
429 // mapping and just use a UUID or other random string.
430 // http://crbug.com/465320
431 std::string MidiManagerAlsa::AlsaPortMetadata::OpaqueKey() const {
432 uint8 hash[crypto::kSHA256Length];
433 crypto::SHA256HashString(JSONValue(), &hash, crypto::kSHA256Length);
agl 2015/03/19 12:05:18 the 3rd argument should be sizeof(hash). (It's the
Adam Goode 2015/03/19 16:48:32 Done.
434 return base::HexEncode(&hash, crypto::kSHA256Length);
435 }
436
437 // TODO(agoode): Add a client->card/rawmidi mapping to the kernel to avoid
438 // needing to probe in this way.
439 ScopedVector<MidiManagerAlsa::AlsaRawmidi> MidiManagerAlsa::AllAlsaRawmidis() {
440 ScopedVector<AlsaRawmidi> devices;
298 snd_ctl_card_info_t* card; 441 snd_ctl_card_info_t* card;
299 snd_rawmidi_info_t* midi_out; 442 snd_rawmidi_info_t* midi_out;
300 snd_rawmidi_info_t* midi_in; 443 snd_rawmidi_info_t* midi_in;
301 snd_ctl_card_info_alloca(&card); 444 snd_ctl_card_info_alloca(&card);
302 snd_rawmidi_info_alloca(&midi_out); 445 snd_rawmidi_info_alloca(&midi_out);
303 snd_rawmidi_info_alloca(&midi_in); 446 snd_rawmidi_info_alloca(&midi_in);
304 for (int card_index = -1; !snd_card_next(&card_index) && card_index >= 0;) { 447 for (int card_index = -1; !snd_card_next(&card_index) && card_index >= 0;) {
305 const std::string id = base::StringPrintf("hw:CARD=%i", card_index); 448 const std::string id = base::StringPrintf("hw:CARD=%i", card_index);
306 snd_ctl_t* handle; 449 snd_ctl_t* handle;
307 int err = snd_ctl_open(&handle, id.c_str(), 0); 450 int err = snd_ctl_open(&handle, id.c_str(), 0);
308 if (err != 0) { 451 if (err != 0) {
309 VLOG(1) << "snd_ctl_open fails: " << snd_strerror(err); 452 VLOG(1) << "snd_ctl_open fails: " << snd_strerror(err);
310 continue; 453 continue;
311 } 454 }
312 err = snd_ctl_card_info(handle, card); 455 err = snd_ctl_card_info(handle, card);
313 if (err != 0) { 456 if (err != 0) {
314 VLOG(1) << "snd_ctl_card_info fails: " << snd_strerror(err); 457 VLOG(1) << "snd_ctl_card_info fails: " << snd_strerror(err);
315 snd_ctl_close(handle); 458 snd_ctl_close(handle);
316 continue; 459 continue;
317 } 460 }
318 // Enumerate any rawmidi devices (not subdevices) and extract MidiDevice. 461 // Enumerate any rawmidi devices (not subdevices) and extract AlsaRawmidi.
319 for (int device = -1; 462 for (int device = -1;
320 !snd_ctl_rawmidi_next_device(handle, &device) && device >= 0;) { 463 !snd_ctl_rawmidi_next_device(handle, &device) && device >= 0;) {
321 bool output; 464 bool output;
322 bool input; 465 bool input;
323 snd_rawmidi_info_set_device(midi_out, device); 466 snd_rawmidi_info_set_device(midi_out, device);
324 snd_rawmidi_info_set_subdevice(midi_out, 0); 467 snd_rawmidi_info_set_subdevice(midi_out, 0);
325 snd_rawmidi_info_set_stream(midi_out, SND_RAWMIDI_STREAM_OUTPUT); 468 snd_rawmidi_info_set_stream(midi_out, SND_RAWMIDI_STREAM_OUTPUT);
326 output = snd_ctl_rawmidi_info(handle, midi_out) == 0; 469 output = snd_ctl_rawmidi_info(handle, midi_out) == 0;
327 snd_rawmidi_info_set_device(midi_in, device); 470 snd_rawmidi_info_set_device(midi_in, device);
328 snd_rawmidi_info_set_subdevice(midi_in, 0); 471 snd_rawmidi_info_set_subdevice(midi_in, 0);
329 snd_rawmidi_info_set_stream(midi_in, SND_RAWMIDI_STREAM_INPUT); 472 snd_rawmidi_info_set_stream(midi_in, SND_RAWMIDI_STREAM_INPUT);
330 input = snd_ctl_rawmidi_info(handle, midi_in) == 0; 473 input = snd_ctl_rawmidi_info(handle, midi_in) == 0;
331 if (!output && !input) 474 if (!output && !input)
332 continue; 475 continue;
333 476
334 // Compute and save ALSA and udev properties. 477 // Compute and save ALSA and udev properties.
335 snd_rawmidi_info_t* midi = midi_out ? midi_out : midi_in; 478 snd_rawmidi_info_t* midi = midi_out ? midi_out : midi_in;
336 devices.push_back(new MidiDevice(this, snd_rawmidi_info_get_name(midi), 479 devices.push_back(new AlsaRawmidi(this, snd_rawmidi_info_get_name(midi),
337 snd_ctl_card_info_get_longname(card), 480 snd_ctl_card_info_get_longname(card),
338 snd_ctl_card_info_get_driver(card), 481 snd_ctl_card_info_get_driver(card),
339 card_index)); 482 card_index));
340 } 483 }
341 snd_ctl_close(handle); 484 snd_ctl_close(handle);
342 } 485 }
343 486
344 return devices.Pass(); 487 return devices.Pass();
345 } 488 }
346 489
347 void MidiManagerAlsa::EnumeratePorts() { 490 void MidiManagerAlsa::EnumeratePorts() {
348 ScopedVector<MidiDevice> devices = AllMidiDevices(); 491 ScopedVector<AlsaRawmidi> devices = AllAlsaRawmidis();
349 492
350 snd_seq_port_subscribe_t* subs; 493 snd_seq_port_subscribe_t* subs;
351 snd_seq_port_subscribe_alloca(&subs); 494 snd_seq_port_subscribe_alloca(&subs);
352 495
353 int in_client_id = snd_seq_client_id(in_client_); 496 int in_client_id = snd_seq_client_id(in_client_);
354 497
355 // Enumerate all clients. 498 // Enumerate all clients.
356 snd_seq_client_info_t* client_info; 499 snd_seq_client_info_t* client_info;
357 snd_seq_client_info_alloca(&client_info); 500 snd_seq_client_info_alloca(&client_info);
358 snd_seq_port_info_t* port_info; 501 snd_seq_port_info_t* port_info;
(...skipping 10 matching lines...) Expand all
369 continue; 512 continue;
370 } 513 }
371 514
372 // Get client metadata. 515 // Get client metadata.
373 const std::string client_name = snd_seq_client_info_get_name(client_info); 516 const std::string client_name = snd_seq_client_info_get_name(client_info);
374 snd_seq_port_info_set_client(port_info, client_id); 517 snd_seq_port_info_set_client(port_info, client_id);
375 snd_seq_port_info_set_port(port_info, -1); 518 snd_seq_port_info_set_port(port_info, -1);
376 519
377 std::string manufacturer; 520 std::string manufacturer;
378 std::string driver; 521 std::string driver;
379 std::string udev_id_path; 522 std::string path;
380 std::string udev_id_id; 523 std::string bus;
524 std::string vendor_id;
525 std::string id;
526 std::string card_name;
527 std::string card_longname;
381 528
382 // Join kernel clients against the list of MidiDevices. 529 // Join kernel clients against the list of AlsaRawmidis.
383 // In the current ALSA kernel implementation, kernel clients match the 530 // In the current ALSA kernel implementation, kernel clients match the
384 // kernel devices in the same order, for devices with client_id over 531 // kernel devices in the same order, for devices with client_id over
385 // kMinimumClientIdForCards. 532 // kMinimumClientIdForCards.
386 if ((snd_seq_client_info_get_type(client_info) == SND_SEQ_KERNEL_CLIENT) && 533 if ((snd_seq_client_info_get_type(client_info) == SND_SEQ_KERNEL_CLIENT) &&
387 (current_device < devices.size()) && 534 (current_device < devices.size()) &&
388 (client_id >= kMinimumClientIdForCards)) { 535 (client_id >= kMinimumClientIdForCards)) {
389 const MidiDevice* device = devices[current_device]; 536 const AlsaRawmidi* device = devices[current_device];
390 manufacturer = device->manufacturer(); 537 manufacturer = device->manufacturer();
391 driver = device->alsa_driver(); 538 driver = device->alsa_driver();
392 udev_id_path = device->udev_id_path(); 539 path = device->path();
393 udev_id_id = device->udev_id_id(); 540 bus = device->bus();
541 vendor_id = device->vendor_id();
542 id = device->id();
543 card_name = device->alsa_name();
544 card_longname = device->alsa_longname();
394 current_device++; 545 current_device++;
395 } 546 }
396 // Enumerate ports. 547 // Enumerate ports.
397 while (!snd_seq_query_next_port(in_client_, port_info)) { 548 while (!snd_seq_query_next_port(in_client_, port_info)) {
398 unsigned int port_type = snd_seq_port_info_get_type(port_info); 549 unsigned int port_type = snd_seq_port_info_get_type(port_info);
399 if (port_type & SND_SEQ_PORT_TYPE_MIDI_GENERIC) { 550 if (port_type & SND_SEQ_PORT_TYPE_MIDI_GENERIC) {
400 const snd_seq_addr_t* addr = snd_seq_port_info_get_addr(port_info); 551 const snd_seq_addr_t* addr = snd_seq_port_info_get_addr(port_info);
401 const std::string name = snd_seq_port_info_get_name(port_info); 552 const std::string name = snd_seq_port_info_get_name(port_info);
402 const std::string id_suffix =
403 base::StringPrintf("%d:%d/%s/%s", addr->client, addr->port,
404 udev_id_path.c_str(), udev_id_id.c_str());
405 std::string version; 553 std::string version;
406 if (!driver.empty()) { 554 if (!driver.empty()) {
407 version = driver + " / "; 555 version = driver + " / ";
408 } 556 }
409 version += base::StringPrintf("ALSA library version %d.%d.%d", 557 version += base::StringPrintf("ALSA library version %d.%d.%d",
410 SND_LIB_MAJOR, 558 SND_LIB_MAJOR,
411 SND_LIB_MINOR, 559 SND_LIB_MINOR,
412 SND_LIB_SUBMINOR); 560 SND_LIB_SUBMINOR);
413 unsigned int caps = snd_seq_port_info_get_capability(port_info); 561 unsigned int caps = snd_seq_port_info_get_capability(port_info);
414 if ((caps & kRequiredInputPortCaps) == kRequiredInputPortCaps) { 562 if ((caps & kRequiredInputPortCaps) == kRequiredInputPortCaps) {
415 // Subscribe to this port. 563 // Subscribe to this port.
416 const snd_seq_addr_t* sender = snd_seq_port_info_get_addr(port_info); 564 const snd_seq_addr_t* sender = snd_seq_port_info_get_addr(port_info);
417 snd_seq_addr_t dest; 565 snd_seq_addr_t dest;
418 dest.client = snd_seq_client_id(in_client_); 566 dest.client = snd_seq_client_id(in_client_);
419 dest.port = in_port_; 567 dest.port = in_port_;
420 snd_seq_port_subscribe_set_sender(subs, sender); 568 snd_seq_port_subscribe_set_sender(subs, sender);
421 snd_seq_port_subscribe_set_dest(subs, &dest); 569 snd_seq_port_subscribe_set_dest(subs, &dest);
422 int err = snd_seq_subscribe_port(in_client_, subs); 570 int err = snd_seq_subscribe_port(in_client_, subs);
423 if (err != 0) { 571 if (err != 0) {
424 VLOG(1) << "snd_seq_subscribe_port fails: " << snd_strerror(err); 572 VLOG(1) << "snd_seq_subscribe_port fails: " << snd_strerror(err);
425 } else { 573 } else {
426 source_map_[AddrToInt(sender)] = current_input++; 574 source_map_[AddrToInt(sender)] = current_input++;
427 AddInputPort( 575 const AlsaPortMetadata metadata(path, bus, id, addr, client_name,
428 MidiPortInfo(base::StringPrintf("input/%s", id_suffix.c_str()), 576 name, card_name, card_longname,
429 manufacturer, name, version, MIDI_PORT_OPENED)); 577 AlsaPortMetadata::Type::kInput);
578 const std::string id = metadata.OpaqueKey();
579 AddInputPort(MidiPortInfo(id.c_str(), manufacturer, name, version,
580 MIDI_PORT_OPENED));
430 } 581 }
431 } 582 }
432 if ((caps & kRequiredOutputPortCaps) == kRequiredOutputPortCaps) { 583 if ((caps & kRequiredOutputPortCaps) == kRequiredOutputPortCaps) {
433 // Create a port for us to send on. 584 // Create a port for us to send on.
434 int out_port = 585 int out_port =
435 snd_seq_create_simple_port(out_client_, NULL, 586 snd_seq_create_simple_port(out_client_, NULL,
436 SND_SEQ_PORT_CAP_READ | 587 SND_SEQ_PORT_CAP_READ |
437 SND_SEQ_PORT_CAP_NO_EXPORT, 588 SND_SEQ_PORT_CAP_NO_EXPORT,
438 SND_SEQ_PORT_TYPE_MIDI_GENERIC | 589 SND_SEQ_PORT_TYPE_MIDI_GENERIC |
439 SND_SEQ_PORT_TYPE_APPLICATION); 590 SND_SEQ_PORT_TYPE_APPLICATION);
440 if (out_port < 0) { 591 if (out_port < 0) {
441 VLOG(1) << "snd_seq_create_simple_port fails: " 592 VLOG(1) << "snd_seq_create_simple_port fails: "
442 << snd_strerror(out_port); 593 << snd_strerror(out_port);
443 // Skip this output port for now. 594 // Skip this output port for now.
444 continue; 595 continue;
445 } 596 }
446 597
447 // Activate port subscription. 598 // Activate port subscription.
448 snd_seq_addr_t sender; 599 snd_seq_addr_t sender;
449 const snd_seq_addr_t* dest = snd_seq_port_info_get_addr(port_info); 600 const snd_seq_addr_t* dest = snd_seq_port_info_get_addr(port_info);
450 sender.client = snd_seq_client_id(out_client_); 601 sender.client = snd_seq_client_id(out_client_);
451 sender.port = out_port; 602 sender.port = out_port;
452 snd_seq_port_subscribe_set_sender(subs, &sender); 603 snd_seq_port_subscribe_set_sender(subs, &sender);
453 snd_seq_port_subscribe_set_dest(subs, dest); 604 snd_seq_port_subscribe_set_dest(subs, dest);
454 int err = snd_seq_subscribe_port(out_client_, subs); 605 int err = snd_seq_subscribe_port(out_client_, subs);
455 if (err != 0) { 606 if (err != 0) {
456 VLOG(1) << "snd_seq_subscribe_port fails: " << snd_strerror(err); 607 VLOG(1) << "snd_seq_subscribe_port fails: " << snd_strerror(err);
457 snd_seq_delete_simple_port(out_client_, out_port); 608 snd_seq_delete_simple_port(out_client_, out_port);
458 } else { 609 } else {
459 snd_midi_event_t* encoder;
460 snd_midi_event_new(kSendBufferSize, &encoder);
461 encoders_.push_back(encoder);
462 out_ports_.push_back(out_port); 610 out_ports_.push_back(out_port);
463 AddOutputPort( 611 const AlsaPortMetadata metadata(path, bus, id, addr, client_name,
464 MidiPortInfo(base::StringPrintf("output/%s", id_suffix.c_str()), 612 name, card_name, card_longname,
465 manufacturer, name, version, MIDI_PORT_OPENED)); 613 AlsaPortMetadata::Type::kOutput);
614 const std::string id = metadata.OpaqueKey();
615 AddOutputPort(MidiPortInfo(id.c_str(), manufacturer, name, version,
616 MIDI_PORT_OPENED));
466 } 617 }
467 } 618 }
468 } 619 }
469 } 620 }
470 } 621 }
471 } 622 }
472 623
473 void MidiManagerAlsa::SendMidiData(uint32 port_index, 624 void MidiManagerAlsa::SendMidiData(uint32 port_index,
474 const std::vector<uint8>& data) { 625 const std::vector<uint8>& data) {
475 DCHECK(send_thread_.message_loop_proxy()->BelongsToCurrentThread()); 626 DCHECK(send_thread_.message_loop_proxy()->BelongsToCurrentThread());
476 627
477 snd_midi_event_t* encoder = encoders_[port_index]; 628 snd_midi_event_t* encoder;
629 snd_midi_event_new(kSendBufferSize, &encoder);
478 for (unsigned int i = 0; i < data.size(); i++) { 630 for (unsigned int i = 0; i < data.size(); i++) {
479 snd_seq_event_t event; 631 snd_seq_event_t event;
480 int result = snd_midi_event_encode_byte(encoder, data[i], &event); 632 int result = snd_midi_event_encode_byte(encoder, data[i], &event);
481 if (result == 1) { 633 if (result == 1) {
482 // Full event, send it. 634 // Full event, send it.
483 snd_seq_ev_set_source(&event, out_ports_[port_index]); 635 snd_seq_ev_set_source(&event, out_ports_[port_index]);
484 snd_seq_ev_set_subs(&event); 636 snd_seq_ev_set_subs(&event);
485 snd_seq_ev_set_direct(&event); 637 snd_seq_ev_set_direct(&event);
486 snd_seq_event_output_direct(out_client_, &event); 638 snd_seq_event_output_direct(out_client_, &event);
487 } 639 }
488 } 640 }
641 snd_midi_event_free(encoder);
489 } 642 }
490 643
491 void MidiManagerAlsa::ScheduleEventLoop() { 644 void MidiManagerAlsa::ScheduleEventLoop() {
492 event_thread_.message_loop()->PostTask( 645 event_thread_.message_loop()->PostTask(
493 FROM_HERE, 646 FROM_HERE,
494 base::Bind(&MidiManagerAlsa::EventLoop, base::Unretained(this))); 647 base::Bind(&MidiManagerAlsa::EventLoop, base::Unretained(this)));
495 } 648 }
496 649
497 void MidiManagerAlsa::EventLoop() { 650 void MidiManagerAlsa::EventLoop() {
498 // Read available incoming MIDI data. 651 // Read available incoming MIDI data.
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
572 } 725 }
573 } 726 }
574 } 727 }
575 } 728 }
576 729
577 MidiManager* MidiManager::Create() { 730 MidiManager* MidiManager::Create() {
578 return new MidiManagerAlsa(); 731 return new MidiManagerAlsa();
579 } 732 }
580 733
581 } // namespace media 734 } // namespace media
OLDNEW
« no previous file with comments | « media/midi/midi_manager_alsa.h ('k') | media/midi/midi_manager_alsa_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698