OLD | NEW |
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> |
(...skipping 243 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
254 device::udev_device_new_from_subsystem_sysname( | 254 device::udev_device_new_from_subsystem_sysname( |
255 outer->udev_.get(), kSoundClass, sysname.c_str())); | 255 outer->udev_.get(), kSoundClass, sysname.c_str())); |
256 | 256 |
257 // TODO(agoode): Move this to a new utility class in device/udev_linux? | 257 // TODO(agoode): Move this to a new utility class in device/udev_linux? |
258 | 258 |
259 // Try to get the vendor string. Sometimes it is encoded. | 259 // Try to get the vendor string. Sometimes it is encoded. |
260 vendor = device::UdevDecodeString( | 260 vendor = device::UdevDecodeString( |
261 device::UdevDeviceGetPropertyValue(udev_device.get(), kIdVendorEnc)); | 261 device::UdevDeviceGetPropertyValue(udev_device.get(), kIdVendorEnc)); |
262 // Sometimes it is not encoded. | 262 // Sometimes it is not encoded. |
263 if (vendor.empty()) | 263 if (vendor.empty()) |
264 UdevDeviceGetPropertyOrSysattr(udev_device.get(), kIdVendor, | 264 vendor = UdevDeviceGetPropertyOrSysattr(udev_device.get(), kIdVendor, |
265 kSysattrVendorName); | 265 kSysattrVendorName); |
266 // Also get the vendor string from the hardware database. | 266 // Also get the vendor string from the hardware database. |
267 vendor_from_database = device::UdevDeviceGetPropertyValue( | 267 vendor_from_database = device::UdevDeviceGetPropertyValue( |
268 udev_device.get(), kIdVendorFromDatabase); | 268 udev_device.get(), kIdVendorFromDatabase); |
269 | 269 |
270 // Get the device path. | 270 // Get the device path. |
271 path_ = device::UdevDeviceGetPropertyValue(udev_device.get(), kIdPath); | 271 path_ = device::UdevDeviceGetPropertyValue(udev_device.get(), kIdPath); |
272 | 272 |
273 // Get the bus. | 273 // Get the bus. |
274 bus_ = device::UdevDeviceGetPropertyValue(udev_device.get(), kIdBus); | 274 bus_ = device::UdevDeviceGetPropertyValue(udev_device.get(), kIdBus); |
275 | 275 |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
337 const std::string& udev_id_vendor_from_database, | 337 const std::string& udev_id_vendor_from_database, |
338 const std::string& alsa_name, | 338 const std::string& alsa_name, |
339 const std::string& alsa_longname) { | 339 const std::string& alsa_longname) { |
340 // Let's try to determine the manufacturer. Here is the ordered preference | 340 // Let's try to determine the manufacturer. Here is the ordered preference |
341 // in extraction: | 341 // in extraction: |
342 // 1. Vendor name from the hardware device string, from udev properties | 342 // 1. Vendor name from the hardware device string, from udev properties |
343 // or sysattrs. | 343 // or sysattrs. |
344 // 2. Vendor name from the udev database (property ID_VENDOR_FROM_DATABASE). | 344 // 2. Vendor name from the udev database (property ID_VENDOR_FROM_DATABASE). |
345 // 3. Heuristic from ALSA. | 345 // 3. Heuristic from ALSA. |
346 | 346 |
347 // Is the vendor string not just the vendor hex id? | 347 // Is the vendor string present and not just the vendor hex id? |
348 if (udev_id_vendor != udev_id_vendor_id) { | 348 if (!udev_id_vendor.empty() && (udev_id_vendor != udev_id_vendor_id)) { |
349 return udev_id_vendor; | 349 return udev_id_vendor; |
350 } | 350 } |
351 | 351 |
352 // Is there a vendor string in the hardware database? | 352 // Is there a vendor string in the hardware database? |
353 if (!udev_id_vendor_from_database.empty()) { | 353 if (!udev_id_vendor_from_database.empty()) { |
354 return udev_id_vendor_from_database; | 354 return udev_id_vendor_from_database; |
355 } | 355 } |
356 | 356 |
357 // Ok, udev gave us nothing useful, or was unavailable. So try a heuristic. | 357 // Ok, udev gave us nothing useful, or was unavailable. So try a heuristic. |
358 // We assume that card longname is in the format of | 358 // We assume that card longname is in the format of |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
434 uint8 hash[crypto::kSHA256Length]; | 434 uint8 hash[crypto::kSHA256Length]; |
435 crypto::SHA256HashString(JSONValue(), &hash, sizeof(hash)); | 435 crypto::SHA256HashString(JSONValue(), &hash, sizeof(hash)); |
436 return base::HexEncode(&hash, sizeof(hash)); | 436 return base::HexEncode(&hash, sizeof(hash)); |
437 } | 437 } |
438 | 438 |
439 // TODO(agoode): Add a client->card/rawmidi mapping to the kernel to avoid | 439 // TODO(agoode): Add a client->card/rawmidi mapping to the kernel to avoid |
440 // needing to probe in this way. | 440 // needing to probe in this way. |
441 ScopedVector<MidiManagerAlsa::AlsaRawmidi> MidiManagerAlsa::AllAlsaRawmidis() { | 441 ScopedVector<MidiManagerAlsa::AlsaRawmidi> MidiManagerAlsa::AllAlsaRawmidis() { |
442 ScopedVector<AlsaRawmidi> devices; | 442 ScopedVector<AlsaRawmidi> devices; |
443 snd_ctl_card_info_t* card; | 443 snd_ctl_card_info_t* card; |
444 snd_rawmidi_info_t* midi_out; | 444 snd_hwdep_info_t* hwdep; |
445 snd_rawmidi_info_t* midi_in; | |
446 snd_ctl_card_info_alloca(&card); | 445 snd_ctl_card_info_alloca(&card); |
447 snd_rawmidi_info_alloca(&midi_out); | 446 snd_hwdep_info_alloca(&hwdep); |
448 snd_rawmidi_info_alloca(&midi_in); | |
449 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;) { |
450 const std::string id = base::StringPrintf("hw:CARD=%i", card_index); | 448 const std::string id = base::StringPrintf("hw:CARD=%i", card_index); |
451 snd_ctl_t* handle; | 449 snd_ctl_t* handle; |
452 int err = snd_ctl_open(&handle, id.c_str(), 0); | 450 int err = snd_ctl_open(&handle, id.c_str(), 0); |
453 if (err != 0) { | 451 if (err != 0) { |
454 VLOG(1) << "snd_ctl_open fails: " << snd_strerror(err); | 452 VLOG(1) << "snd_ctl_open fails: " << snd_strerror(err); |
455 continue; | 453 continue; |
456 } | 454 } |
457 err = snd_ctl_card_info(handle, card); | 455 err = snd_ctl_card_info(handle, card); |
458 if (err != 0) { | 456 if (err != 0) { |
459 VLOG(1) << "snd_ctl_card_info fails: " << snd_strerror(err); | 457 VLOG(1) << "snd_ctl_card_info fails: " << snd_strerror(err); |
460 snd_ctl_close(handle); | 458 snd_ctl_close(handle); |
461 continue; | 459 continue; |
462 } | 460 } |
463 // Enumerate any rawmidi devices (not subdevices) and extract AlsaRawmidi. | 461 std::string name = snd_ctl_card_info_get_name(card); |
| 462 std::string longname = snd_ctl_card_info_get_longname(card); |
| 463 std::string driver = snd_ctl_card_info_get_driver(card); |
| 464 |
| 465 // Count rawmidi devices (not subdevices). |
464 for (int device = -1; | 466 for (int device = -1; |
465 !snd_ctl_rawmidi_next_device(handle, &device) && device >= 0;) { | 467 !snd_ctl_rawmidi_next_device(handle, &device) && device >= 0;) { |
466 bool output; | 468 devices.push_back( |
467 bool input; | 469 new AlsaRawmidi(this, name, longname, driver, card_index)); |
468 snd_rawmidi_info_set_device(midi_out, device); | 470 } |
469 snd_rawmidi_info_set_subdevice(midi_out, 0); | |
470 snd_rawmidi_info_set_stream(midi_out, SND_RAWMIDI_STREAM_OUTPUT); | |
471 output = snd_ctl_rawmidi_info(handle, midi_out) == 0; | |
472 snd_rawmidi_info_set_device(midi_in, device); | |
473 snd_rawmidi_info_set_subdevice(midi_in, 0); | |
474 snd_rawmidi_info_set_stream(midi_in, SND_RAWMIDI_STREAM_INPUT); | |
475 input = snd_ctl_rawmidi_info(handle, midi_in) == 0; | |
476 if (!output && !input) | |
477 continue; | |
478 | 471 |
479 // Compute and save ALSA and udev properties. | 472 // Count any hwdep synths that become MIDI devices. |
480 snd_rawmidi_info_t* midi = midi_out ? midi_out : midi_in; | 473 // |
481 devices.push_back(new AlsaRawmidi(this, snd_rawmidi_info_get_name(midi), | 474 // Explanation: |
482 snd_ctl_card_info_get_longname(card), | 475 // Any kernel driver can create an ALSA client (visible to us). |
483 snd_ctl_card_info_get_driver(card), | 476 // With modern hardware, only rawmidi devices do this. Kernel |
484 card_index)); | 477 // drivers create rawmidi devices and the rawmidi subsystem makes |
| 478 // the seq clients. But the OPL3 driver is special, it does not |
| 479 // make a rawmidi device but a seq client directly. (This is the |
| 480 // only one to worry about in the kernel code, as of 2015-03-23.) |
| 481 // |
| 482 // OPL3 is very old (but still possible to get in new |
| 483 // hardware). It is unlikely that new drivers would not use |
| 484 // rawmidi and defeat our heuristic. |
| 485 // |
| 486 // Longer term, support should be added in the kernel to expose a |
| 487 // direct link from card->client (or client->card) so that all |
| 488 // these heuristics will be obsolete. Once that is there, we can |
| 489 // assume our old heuristics will work on old kernels and the new |
| 490 // robust code will be used on new. Then we will not need to worry |
| 491 // about changes to kernel internals breaking our code. |
| 492 // See the TODO above at kMinimumClientIdForCards. |
| 493 for (int device = -1; |
| 494 !snd_ctl_hwdep_next_device(handle, &device) && device >= 0;) { |
| 495 snd_ctl_hwdep_info(handle, hwdep); |
| 496 snd_hwdep_iface_t iface = snd_hwdep_info_get_iface(hwdep); |
| 497 if (iface == SND_HWDEP_IFACE_OPL2 || iface == SND_HWDEP_IFACE_OPL3 || |
| 498 iface == SND_HWDEP_IFACE_OPL4) |
| 499 devices.push_back( |
| 500 new AlsaRawmidi(this, name, longname, driver, card_index)); |
485 } | 501 } |
486 snd_ctl_close(handle); | 502 snd_ctl_close(handle); |
487 } | 503 } |
488 | 504 |
489 return devices.Pass(); | 505 return devices.Pass(); |
490 } | 506 } |
491 | 507 |
492 void MidiManagerAlsa::EnumeratePorts() { | 508 void MidiManagerAlsa::EnumeratePorts() { |
493 ScopedVector<AlsaRawmidi> devices = AllAlsaRawmidis(); | 509 ScopedVector<AlsaRawmidi> devices = AllAlsaRawmidis(); |
494 | 510 |
(...skipping 232 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
727 } | 743 } |
728 } | 744 } |
729 } | 745 } |
730 } | 746 } |
731 | 747 |
732 MidiManager* MidiManager::Create() { | 748 MidiManager* MidiManager::Create() { |
733 return new MidiManagerAlsa(); | 749 return new MidiManagerAlsa(); |
734 } | 750 } |
735 | 751 |
736 } // namespace media | 752 } // namespace media |
OLD | NEW |