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

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

Issue 1025863002: Web MIDI Linux: Fix enumeration when OPL3 devices are present, and fix manufacturer extraction bugs (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Add comments about why we special case OPL3, reformat 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 | « no previous file | 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>
(...skipping 243 matching lines...) Expand 10 before | Expand all | Expand 10 after
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
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
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
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
OLDNEW
« no previous file with comments | « no previous file | media/midi/midi_manager_alsa_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698