| 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> |
| 11 | 11 |
| 12 #include "base/bind.h" | 12 #include "base/bind.h" |
| 13 #include "base/logging.h" | 13 #include "base/logging.h" |
| 14 #include "base/memory/ref_counted.h" | 14 #include "base/memory/ref_counted.h" |
| 15 #include "base/memory/scoped_vector.h" | 15 #include "base/memory/scoped_vector.h" |
| 16 #include "base/message_loop/message_loop.h" | 16 #include "base/message_loop/message_loop.h" |
| 17 #include "base/posix/eintr_wrapper.h" | 17 #include "base/posix/eintr_wrapper.h" |
| 18 #include "base/strings/string_util.h" | |
| 19 #include "base/strings/stringprintf.h" | 18 #include "base/strings/stringprintf.h" |
| 20 #include "base/threading/thread.h" | 19 #include "base/threading/thread.h" |
| 21 #include "base/time/time.h" | 20 #include "base/time/time.h" |
| 22 #include "media/midi/midi_port_info.h" | 21 #include "media/midi/midi_port_info.h" |
| 23 | 22 |
| 24 namespace media { | 23 namespace media { |
| 25 | 24 |
| 26 namespace { | 25 namespace { |
| 27 | 26 |
| 28 // Per-output buffer. This can be smaller, but then large sysex messages | 27 // Per-output buffer. This can be smaller, but then large sysex messages |
| 29 // will be (harmlessly) split across multiple seq events. This should | 28 // will be (harmlessly) split across multiple seq events. This should |
| 30 // not have any real practical effect, except perhaps to slightly reorder | 29 // not have any real practical effect, except perhaps to slightly reorder |
| 31 // realtime messages with respect to sysex. | 30 // realtime messages with respect to sysex. |
| 32 const size_t kSendBufferSize = 256; | 31 const size_t kSendBufferSize = 256; |
| 33 | 32 |
| 34 // Constants for the capabilities we search for in inputs and outputs. | 33 // Constants for the capabilities we search for in inputs and outputs. |
| 35 // See http://www.alsa-project.org/alsa-doc/alsa-lib/seq.html. | 34 // See http://www.alsa-project.org/alsa-doc/alsa-lib/seq.html. |
| 36 const unsigned int kRequiredInputPortCaps = | 35 const unsigned int kRequiredInputPortCaps = |
| 37 SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_READ; | 36 SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_READ; |
| 38 const unsigned int kRequiredOutputPortCaps = | 37 const unsigned int kRequiredOutputPortCaps = |
| 39 SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE; | 38 SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE; |
| 40 | 39 |
| 41 int AddrToInt(const snd_seq_addr_t* addr) { | 40 int AddrToInt(const snd_seq_addr_t* addr) { |
| 42 return (addr->client << 8) | addr->port; | 41 return (addr->client << 8) | addr->port; |
| 43 } | 42 } |
| 44 | 43 |
| 45 #if defined(USE_UDEV) | |
| 46 // Copied from components/storage_monitor/udev_util_linux.cc. | |
| 47 // TODO(agoode): Move this into a common place. Maybe device/udev_linux? | |
| 48 std::string GetUdevDevicePropertyValue(udev_device* udev_device, | |
| 49 const char* key) { | |
| 50 const char* value = device::udev_device_get_property_value(udev_device, key); | |
| 51 return value ? value : std::string(); | |
| 52 } | |
| 53 #endif // defined(USE_UDEV) | |
| 54 | |
| 55 } // namespace | 44 } // namespace |
| 56 | 45 |
| 57 MidiManagerAlsa::MidiManagerAlsa() | 46 MidiManagerAlsa::MidiManagerAlsa() |
| 58 : in_client_(NULL), | 47 : in_client_(NULL), |
| 59 out_client_(NULL), | 48 out_client_(NULL), |
| 60 out_client_id_(-1), | 49 out_client_id_(-1), |
| 61 in_port_(-1), | 50 in_port_(-1), |
| 62 decoder_(NULL), | 51 decoder_(NULL), |
| 63 #if defined(USE_UDEV) | 52 #if defined(USE_UDEV) |
| 64 udev_(device::udev_new()), | 53 udev_(device::udev_new()), |
| (...skipping 263 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 328 for (EncoderList::iterator i = encoders_.begin(); i != encoders_.end(); ++i) | 317 for (EncoderList::iterator i = encoders_.begin(); i != encoders_.end(); ++i) |
| 329 snd_midi_event_free(*i); | 318 snd_midi_event_free(*i); |
| 330 } | 319 } |
| 331 | 320 |
| 332 MidiManagerAlsa::CardInfo::CardInfo( | 321 MidiManagerAlsa::CardInfo::CardInfo( |
| 333 const MidiManagerAlsa* outer, | 322 const MidiManagerAlsa* outer, |
| 334 const std::string& alsa_name, const std::string& alsa_longname, | 323 const std::string& alsa_name, const std::string& alsa_longname, |
| 335 const std::string& alsa_driver, int card_index) | 324 const std::string& alsa_driver, int card_index) |
| 336 : alsa_name_(alsa_name), alsa_driver_(alsa_driver) { | 325 : alsa_name_(alsa_name), alsa_driver_(alsa_driver) { |
| 337 // Get udev properties if available. | 326 // Get udev properties if available. |
| 338 std::string udev_id_vendor_enc; | 327 std::string udev_id_vendor; |
| 339 std::string udev_id_vendor_id; | 328 std::string udev_id_vendor_id; |
| 340 std::string udev_id_vendor_from_database; | 329 std::string udev_id_vendor_from_database; |
| 341 | 330 |
| 342 #if defined(USE_UDEV) | 331 #if defined(USE_UDEV) |
| 343 const std::string sysname = base::StringPrintf("card%i", card_index); | 332 const std::string sysname = base::StringPrintf("card%i", card_index); |
| 344 device::ScopedUdevDevicePtr udev_device( | 333 device::ScopedUdevDevicePtr udev_device( |
| 345 device::udev_device_new_from_subsystem_sysname( | 334 device::udev_device_new_from_subsystem_sysname( |
| 346 outer->udev_.get(), "sound", sysname.c_str())); | 335 outer->udev_.get(), "sound", sysname.c_str())); |
| 347 udev_id_vendor_enc = GetUdevDevicePropertyValue( | 336 udev_id_vendor = device::UdevDecodeString(device::UdevDeviceGetPropertyValue( |
| 348 udev_device.get(), "ID_VENDOR_ENC"); | 337 udev_device.get(), "ID_VENDOR_ENC")); |
| 349 udev_id_vendor_id = GetUdevDevicePropertyValue( | 338 udev_id_vendor_id = device::UdevDeviceGetPropertyValue( |
| 350 udev_device.get(), "ID_VENDOR_ID"); | 339 udev_device.get(), "ID_VENDOR_ID"); |
| 351 udev_id_vendor_from_database = GetUdevDevicePropertyValue( | 340 udev_id_vendor_from_database = device::UdevDeviceGetPropertyValue( |
| 352 udev_device.get(), "ID_VENDOR_FROM_DATABASE"); | 341 udev_device.get(), "ID_VENDOR_FROM_DATABASE"); |
| 353 | 342 |
| 354 udev_id_path_ = GetUdevDevicePropertyValue( | 343 udev_id_path_ = device::UdevDeviceGetPropertyValue( |
| 355 udev_device.get(), "ID_PATH"); | 344 udev_device.get(), "ID_PATH"); |
| 356 udev_id_id_ = GetUdevDevicePropertyValue( | 345 udev_id_id_ = device::UdevDeviceGetPropertyValue( |
| 357 udev_device.get(), "ID_ID"); | 346 udev_device.get(), "ID_ID"); |
| 358 #endif // defined(USE_UDEV) | 347 #endif // defined(USE_UDEV) |
| 359 | 348 |
| 360 manufacturer_ = ExtractManufacturerString( | 349 manufacturer_ = ExtractManufacturerString( |
| 361 udev_id_vendor_enc, udev_id_vendor_id, udev_id_vendor_from_database, | 350 udev_id_vendor, udev_id_vendor_id, udev_id_vendor_from_database, |
| 362 alsa_name, alsa_longname); | 351 alsa_name, alsa_longname); |
| 363 } | 352 } |
| 364 | 353 |
| 365 MidiManagerAlsa::CardInfo::~CardInfo() { | 354 MidiManagerAlsa::CardInfo::~CardInfo() { |
| 366 } | 355 } |
| 367 | 356 |
| 368 const std::string MidiManagerAlsa::CardInfo::alsa_name() const { | 357 const std::string MidiManagerAlsa::CardInfo::alsa_name() const { |
| 369 return alsa_name_; | 358 return alsa_name_; |
| 370 } | 359 } |
| 371 | 360 |
| (...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 492 } | 481 } |
| 493 | 482 |
| 494 // Do again. | 483 // Do again. |
| 495 event_thread_.message_loop()->PostTask( | 484 event_thread_.message_loop()->PostTask( |
| 496 FROM_HERE, | 485 FROM_HERE, |
| 497 base::Bind(&MidiManagerAlsa::EventLoop, base::Unretained(this))); | 486 base::Bind(&MidiManagerAlsa::EventLoop, base::Unretained(this))); |
| 498 } | 487 } |
| 499 | 488 |
| 500 // static | 489 // static |
| 501 std::string MidiManagerAlsa::CardInfo::ExtractManufacturerString( | 490 std::string MidiManagerAlsa::CardInfo::ExtractManufacturerString( |
| 502 const std::string& udev_id_vendor_enc, | 491 const std::string& udev_id_vendor, |
| 503 const std::string& udev_id_vendor_id, | 492 const std::string& udev_id_vendor_id, |
| 504 const std::string& udev_id_vendor_from_database, | 493 const std::string& udev_id_vendor_from_database, |
| 505 const std::string& alsa_name, | 494 const std::string& alsa_name, |
| 506 const std::string& alsa_longname) { | 495 const std::string& alsa_longname) { |
| 507 // Let's try to determine the manufacturer. Here is the ordered preference | 496 // Let's try to determine the manufacturer. Here is the ordered preference |
| 508 // in extraction: | 497 // in extraction: |
| 509 // 1. Vendor name from the USB device iManufacturer string, stored in | 498 // 1. Vendor name from the USB device iManufacturer string, from |
| 510 // udev_id_vendor_enc. | 499 // the udev property ID_VENDOR_ENC. |
| 511 // 2. Vendor name from the udev hwid database. | 500 // 2. Vendor name from the udev database (property ID_VENDOR_FROM_DATABASE). |
| 512 // 3. Heuristic from ALSA. | 501 // 3. Heuristic from ALSA. |
| 513 | 502 |
| 514 // Is the vendor string not just the USB vendor hex id? | 503 // Is the vendor string not just the USB vendor hex id? |
| 515 std::string udev_id_vendor = UnescapeUdev(udev_id_vendor_enc); | |
| 516 if (udev_id_vendor != udev_id_vendor_id) { | 504 if (udev_id_vendor != udev_id_vendor_id) { |
| 517 return udev_id_vendor; | 505 return udev_id_vendor; |
| 518 } | 506 } |
| 519 | 507 |
| 520 // Is there a vendor string in the hardware database? | 508 // Is there a vendor string in the hardware database? |
| 521 if (!udev_id_vendor_from_database.empty()) { | 509 if (!udev_id_vendor_from_database.empty()) { |
| 522 return udev_id_vendor_from_database; | 510 return udev_id_vendor_from_database; |
| 523 } | 511 } |
| 524 | 512 |
| 525 // Ok, udev gave us nothing useful, or was unavailable. So try a heuristic. | 513 // Ok, udev gave us nothing useful, or was unavailable. So try a heuristic. |
| 526 // We assume that card longname is in the format of | 514 // We assume that card longname is in the format of |
| 527 // "<manufacturer> <name> at <bus>". Otherwise, we give up to detect | 515 // "<manufacturer> <name> at <bus>". Otherwise, we give up to detect |
| 528 // a manufacturer name here. | 516 // a manufacturer name here. |
| 529 size_t at_index = alsa_longname.rfind(" at "); | 517 size_t at_index = alsa_longname.rfind(" at "); |
| 530 if (std::string::npos != at_index) { | 518 if (std::string::npos != at_index) { |
| 531 size_t name_index = alsa_longname.rfind(alsa_name, at_index - 1); | 519 size_t name_index = alsa_longname.rfind(alsa_name, at_index - 1); |
| 532 if (std::string::npos != name_index) | 520 if (std::string::npos != name_index) |
| 533 return alsa_longname.substr(0, name_index - 1); | 521 return alsa_longname.substr(0, name_index - 1); |
| 534 } | 522 } |
| 535 | 523 |
| 536 // Failure. | 524 // Failure. |
| 537 return ""; | 525 return ""; |
| 538 } | 526 } |
| 539 | 527 |
| 540 // static | |
| 541 std::string MidiManagerAlsa::CardInfo::UnescapeUdev(const std::string& s) { | |
| 542 std::string unescaped; | |
| 543 const size_t size = s.size(); | |
| 544 for (size_t i = 0; i < size; ++i) { | |
| 545 char c = s[i]; | |
| 546 if ((i + 3 < size) && c == '\\' && s[i + 1] == 'x') { | |
| 547 c = (HexDigitToInt(s[i + 2]) << 4) + | |
| 548 HexDigitToInt(s[i + 3]); | |
| 549 i += 3; | |
| 550 } | |
| 551 unescaped.push_back(c); | |
| 552 } | |
| 553 return unescaped; | |
| 554 } | |
| 555 | |
| 556 MidiManager* MidiManager::Create() { | 528 MidiManager* MidiManager::Create() { |
| 557 return new MidiManagerAlsa(); | 529 return new MidiManagerAlsa(); |
| 558 } | 530 } |
| 559 | 531 |
| 560 } // namespace media | 532 } // namespace media |
| OLD | NEW |