Index: media/midi/midi_manager_alsa.cc |
diff --git a/media/midi/midi_manager_alsa.cc b/media/midi/midi_manager_alsa.cc |
index 9043f1f8cc1223eff2cf268053f25240d979ffb6..6dbae8c7f8cfe411bf00e3094b386b9eae9dd6a1 100644 |
--- a/media/midi/midi_manager_alsa.cc |
+++ b/media/midi/midi_manager_alsa.cc |
@@ -15,6 +15,7 @@ |
#include "base/memory/scoped_vector.h" |
#include "base/message_loop/message_loop.h" |
#include "base/posix/eintr_wrapper.h" |
+#include "base/strings/string_util.h" |
#include "base/strings/stringprintf.h" |
#include "base/threading/thread.h" |
#include "base/time/time.h" |
@@ -41,6 +42,15 @@ int AddrToInt(const snd_seq_addr_t* addr) { |
return (addr->client << 8) | addr->port; |
} |
+#if defined(USE_UDEV) |
+// Copied from components/storage_monitor/udev_util_linux.cc. |
+std::string GetUdevDevicePropertyValue(udev_device* udev_device, |
+ const char* key) { |
+ const char* value = device::udev_device_get_property_value(udev_device, key); |
+ return value ? value : std::string(); |
+} |
+#endif // defined(USE_UDEV) |
+ |
class CardInfo { |
public: |
CardInfo(const std::string name, const std::string manufacturer, |
@@ -60,6 +70,9 @@ MidiManagerAlsa::MidiManagerAlsa() |
out_client_id_(-1), |
in_port_(-1), |
decoder_(NULL), |
+#if defined(USE_UDEV) |
+ udev_(device::udev_new()), |
+#endif // defined(USE_UDEV) |
send_thread_("MidiSendThread"), |
event_thread_("MidiEventThread"), |
event_thread_shutdown_(false) { |
@@ -126,11 +139,9 @@ void MidiManagerAlsa::StartInitialization() { |
return CompleteInitialization(MIDI_INITIALIZATION_ERROR); |
} |
- // Use a heuristic to extract the list of manufacturers for the hardware MIDI |
+ // Extract the list of manufacturers for the hardware MIDI |
// devices. This won't work for all devices. It is also brittle until |
// hotplug is implemented. (See http://crbug.com/279097.) |
- // TODO(agoode): Make manufacturer extraction simple and reliable. |
- // http://crbug.com/377250. |
ScopedVector<CardInfo> cards; |
snd_ctl_card_info_t* card; |
snd_rawmidi_info_t* midi_out; |
@@ -138,8 +149,8 @@ void MidiManagerAlsa::StartInitialization() { |
snd_ctl_card_info_alloca(&card); |
snd_rawmidi_info_alloca(&midi_out); |
snd_rawmidi_info_alloca(&midi_in); |
- for (int index = -1; !snd_card_next(&index) && index >= 0; ) { |
- const std::string id = base::StringPrintf("hw:CARD=%i", index); |
+ for (int card_index = -1; !snd_card_next(&card_index) && card_index >= 0; ) { |
+ const std::string id = base::StringPrintf("hw:CARD=%i", card_index); |
snd_ctl_t* handle; |
int err = snd_ctl_open(&handle, id.c_str(), 0); |
if (err != 0) { |
@@ -168,20 +179,33 @@ void MidiManagerAlsa::StartInitialization() { |
if (!output && !input) |
continue; |
+ // Get Alsa properties. |
snd_rawmidi_info_t* midi = midi_out ? midi_out : midi_in; |
const std::string name = snd_rawmidi_info_get_name(midi); |
- // We assume that card longname is in the format of |
- // "<manufacturer> <name> at <bus>". Otherwise, we give up to detect |
- // a manufacturer name here. |
- std::string manufacturer; |
- const std::string card_name = snd_ctl_card_info_get_longname(card); |
- size_t at_index = card_name.rfind(" at "); |
- if (std::string::npos != at_index) { |
- size_t name_index = card_name.rfind(name, at_index - 1); |
- if (std::string::npos != name_index) |
- manufacturer = card_name.substr(0, name_index - 1); |
- } |
+ const std::string longname = snd_ctl_card_info_get_longname(card); |
const std::string driver = snd_ctl_card_info_get_driver(card); |
+ |
+ // Get udev properties if available. |
+ std::string udev_id_vendor_enc; |
+ std::string udev_id_vendor_id; |
+ std::string udev_id_vendor_from_database; |
+#if defined(USE_UDEV) |
+ const std::string sysname = base::StringPrintf("card%i", card_index); |
+ device::ScopedUdevDevicePtr udev_device( |
+ device::udev_device_new_from_subsystem_sysname( |
+ udev_.get(), "sound", sysname.c_str())); |
+ udev_id_vendor_enc = GetUdevDevicePropertyValue( |
+ udev_device.get(), "ID_VENDOR_ENC"); |
+ udev_id_vendor_id = GetUdevDevicePropertyValue( |
+ udev_device.get(), "ID_VENDOR_ID"); |
+ udev_id_vendor_from_database = GetUdevDevicePropertyValue( |
+ udev_device.get(), "ID_VENDOR_FROM_DATABASE"); |
+#endif // defined(USE_UDEV) |
+ |
+ const std::string manufacturer = ExtractManufacturer( |
+ udev_id_vendor_enc, udev_id_vendor_id, udev_id_vendor_from_database, |
+ name, longname); |
+ |
cards.push_back(new CardInfo(name, manufacturer, driver)); |
} |
snd_ctl_close(handle); |
@@ -447,6 +471,60 @@ void MidiManagerAlsa::EventLoop() { |
base::Bind(&MidiManagerAlsa::EventLoop, base::Unretained(this))); |
} |
+std::string MidiManagerAlsa::UnescapeUdev(const std::string& s) { |
wolenetz
2015/03/04 22:18:35
nit: style: "Function declaration order should mat
Adam Goode
2015/03/04 22:57:35
Done.
|
+ std::string unescaped; |
+ const size_t size = s.size(); |
+ for (size_t i = 0; i < size; ++i) { |
+ char c = s[i]; |
+ if ((i + 3 < size) && c == '\\' && s[i + 1] == 'x') { |
+ c = (HexDigitToInt(s[i + 2]) << 4) + |
+ HexDigitToInt(s[i + 3]); |
+ i += 3; |
+ } |
+ unescaped.push_back(c); |
+ } |
+ return unescaped; |
+} |
+ |
+std::string MidiManagerAlsa::ExtractManufacturer( |
+ const std::string& udev_id_vendor_enc, |
+ const std::string& udev_id_vendor_id, |
+ const std::string& udev_id_vendor_from_database, |
+ const std::string& alsa_name, |
+ const std::string& alsa_longname) { |
+ // Let's try to determine the manufacturer. Here is the ordered preference |
+ // in extraction: |
+ // 1. Vendor name from the USB device iManufacturer string, stored in |
+ // udev_id_vendor_enc. |
+ // 2. Vendor name from the udev hwid database. |
+ // 3. Heuristic from ALSA. |
+ |
+ // Is the vendor string not just the USB vendor hex id? |
+ std::string udev_id_vendor = UnescapeUdev(udev_id_vendor_enc); |
+ if (udev_id_vendor != udev_id_vendor_id) { |
+ return udev_id_vendor; |
+ } |
+ |
+ // Is there a vendor string in the hardware database? |
+ if (!udev_id_vendor_from_database.empty()) { |
+ return udev_id_vendor_from_database; |
+ } |
+ |
+ // Ok, udev gave us nothing useful. So try a heuristic. |
+ // We assume that card longname is in the format of |
+ // "<manufacturer> <name> at <bus>". Otherwise, we give up to detect |
+ // a manufacturer name here. |
+ size_t at_index = alsa_longname.rfind(" at "); |
+ if (std::string::npos != at_index) { |
+ size_t name_index = alsa_longname.rfind(alsa_name, at_index - 1); |
+ if (std::string::npos != name_index) |
+ return alsa_longname.substr(0, name_index - 1); |
+ } |
+ |
+ // Failure. |
+ return ""; |
+} |
+ |
MidiManager* MidiManager::Create() { |
return new MidiManagerAlsa(); |
} |