| 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 <poll.h> | 8 #include <poll.h> |
| 9 #include <stdlib.h> | 9 #include <stdlib.h> |
| 10 #include <algorithm> | 10 #include <algorithm> |
| (...skipping 19 matching lines...) Expand all Loading... |
| 30 namespace midi { | 30 namespace midi { |
| 31 | 31 |
| 32 namespace { | 32 namespace { |
| 33 | 33 |
| 34 // Per-output buffer. This can be smaller, but then large sysex messages | 34 // Per-output buffer. This can be smaller, but then large sysex messages |
| 35 // will be (harmlessly) split across multiple seq events. This should | 35 // will be (harmlessly) split across multiple seq events. This should |
| 36 // not have any real practical effect, except perhaps to slightly reorder | 36 // not have any real practical effect, except perhaps to slightly reorder |
| 37 // realtime messages with respect to sysex. | 37 // realtime messages with respect to sysex. |
| 38 const size_t kSendBufferSize = 256; | 38 const size_t kSendBufferSize = 256; |
| 39 | 39 |
| 40 // Minimum client id for which we will have ALSA card devices for. When we |
| 41 // are searching for card devices (used to get the path, id, and manufacturer), |
| 42 // we don't want to get confused by kernel clients that do not have a card. |
| 43 // See seq_clientmgr.c in the ALSA code for this. |
| 44 // TODO(agoode): Add proper client -> card export from the kernel to avoid |
| 45 // hardcoding. |
| 46 const int kMinimumClientIdForCards = 16; |
| 47 |
| 40 // ALSA constants. | 48 // ALSA constants. |
| 41 const char kAlsaHw[] = "hw"; | 49 const char kAlsaHw[] = "hw"; |
| 42 | 50 |
| 43 // udev constants. | 51 // udev constants. |
| 44 const char kUdev[] = "udev"; | 52 const char kUdev[] = "udev"; |
| 45 const char kUdevSubsystemSound[] = "sound"; | 53 const char kUdevSubsystemSound[] = "sound"; |
| 46 const char kUdevPropertySoundInitialized[] = "SOUND_INITIALIZED"; | 54 const char kUdevPropertySoundInitialized[] = "SOUND_INITIALIZED"; |
| 47 const char kUdevActionChange[] = "change"; | 55 const char kUdevActionChange[] = "change"; |
| 48 const char kUdevActionRemove[] = "remove"; | 56 const char kUdevActionRemove[] = "remove"; |
| 49 | 57 |
| 58 const char kUdevIdVendor[] = "ID_VENDOR"; |
| 59 const char kUdevIdVendorEnc[] = "ID_VENDOR_ENC"; |
| 60 const char kUdevIdVendorFromDatabase[] = "ID_VENDOR_FROM_DATABASE"; |
| 61 const char kUdevIdVendorId[] = "ID_VENDOR_ID"; |
| 62 const char kUdevIdModelId[] = "ID_MODEL_ID"; |
| 63 const char kUdevIdBus[] = "ID_BUS"; |
| 64 const char kUdevIdPath[] = "ID_PATH"; |
| 65 const char kUdevIdUsbInterfaceNum[] = "ID_USB_INTERFACE_NUM"; |
| 66 const char kUdevIdSerialShort[] = "ID_SERIAL_SHORT"; |
| 67 |
| 68 const char kSysattrVendorName[] = "vendor_name"; |
| 69 const char kSysattrVendor[] = "vendor"; |
| 70 const char kSysattrModel[] = "model"; |
| 71 const char kSysattrGuid[] = "guid"; |
| 72 |
| 73 const char kCardSyspath[] = "/card"; |
| 74 |
| 50 // Constants for the capabilities we search for in inputs and outputs. | 75 // Constants for the capabilities we search for in inputs and outputs. |
| 51 // See http://www.alsa-project.org/alsa-doc/alsa-lib/seq.html. | 76 // See http://www.alsa-project.org/alsa-doc/alsa-lib/seq.html. |
| 52 const unsigned int kRequiredInputPortCaps = | 77 const unsigned int kRequiredInputPortCaps = |
| 53 SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_READ; | 78 SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_READ; |
| 54 const unsigned int kRequiredOutputPortCaps = | 79 const unsigned int kRequiredOutputPortCaps = |
| 55 SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE; | 80 SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE; |
| 56 | 81 |
| 57 const unsigned int kCreateOutputPortCaps = | 82 const unsigned int kCreateOutputPortCaps = |
| 58 SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_NO_EXPORT; | 83 SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_NO_EXPORT; |
| 59 const unsigned int kCreateInputPortCaps = | 84 const unsigned int kCreateInputPortCaps = |
| 60 SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_NO_EXPORT; | 85 SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_NO_EXPORT; |
| 61 const unsigned int kCreatePortType = | 86 const unsigned int kCreatePortType = |
| 62 SND_SEQ_PORT_TYPE_MIDI_GENERIC | SND_SEQ_PORT_TYPE_APPLICATION; | 87 SND_SEQ_PORT_TYPE_MIDI_GENERIC | SND_SEQ_PORT_TYPE_APPLICATION; |
| 63 | 88 |
| 64 int AddrToInt(int client, int port) { | 89 int AddrToInt(int client, int port) { |
| 65 return (client << 8) | port; | 90 return (client << 8) | port; |
| 66 } | 91 } |
| 67 | 92 |
| 93 // Returns true if this client has an ALSA card associated with it. |
| 94 bool IsCardClient(snd_seq_client_type_t type, int client_id) { |
| 95 return (type == SND_SEQ_KERNEL_CLIENT) && |
| 96 (client_id >= kMinimumClientIdForCards); |
| 97 } |
| 98 |
| 99 // TODO(agoode): Move this to device/udev_linux. |
| 100 const std::string UdevDeviceGetPropertyOrSysattr( |
| 101 struct udev_device* udev_device, |
| 102 const char* property_key, |
| 103 const char* sysattr_key) { |
| 104 // First try the property. |
| 105 std::string value = |
| 106 device::UdevDeviceGetPropertyValue(udev_device, property_key); |
| 107 |
| 108 // If no property, look for sysattrs and walk up the parent devices too. |
| 109 while (value.empty() && udev_device) { |
| 110 value = device::UdevDeviceGetSysattrValue(udev_device, sysattr_key); |
| 111 udev_device = device::udev_device_get_parent(udev_device); |
| 112 } |
| 113 return value; |
| 114 } |
| 115 |
| 116 int GetCardNumber(udev_device* dev) { |
| 117 const char* syspath = device::udev_device_get_syspath(dev); |
| 118 if (!syspath) |
| 119 return -1; |
| 120 |
| 121 std::string syspath_str(syspath); |
| 122 size_t i = syspath_str.rfind(kCardSyspath); |
| 123 if (i == std::string::npos) |
| 124 return -1; |
| 125 |
| 126 int number; |
| 127 if (!base::StringToInt(syspath_str.substr(i + strlen(kCardSyspath)), &number)) |
| 128 return -1; |
| 129 return number; |
| 130 } |
| 131 |
| 68 void SetStringIfNonEmpty(base::DictionaryValue* value, | 132 void SetStringIfNonEmpty(base::DictionaryValue* value, |
| 69 const std::string& path, | 133 const std::string& path, |
| 70 const std::string& in_value) { | 134 const std::string& in_value) { |
| 71 if (!in_value.empty()) | 135 if (!in_value.empty()) |
| 72 value->SetString(path, in_value); | 136 value->SetString(path, in_value); |
| 73 } | 137 } |
| 74 | 138 |
| 75 } // namespace | 139 } // namespace |
| 76 | 140 |
| 77 MidiManagerAlsa::MidiManagerAlsa() | 141 MidiManagerAlsa::MidiManagerAlsa() |
| 78 : in_client_(NULL), | 142 : in_client_(NULL), |
| 79 out_client_(NULL), | 143 out_client_(NULL), |
| 80 out_client_id_(-1), | 144 out_client_id_(-1), |
| 81 in_port_id_(-1), | 145 in_port_id_(-1), |
| 146 alsa_cards_deleter_(&alsa_cards_), |
| 147 alsa_card_midi_count_(0), |
| 82 decoder_(NULL), | 148 decoder_(NULL), |
| 83 udev_(device::udev_new()), | 149 udev_(device::udev_new()), |
| 84 send_thread_("MidiSendThread"), | 150 send_thread_("MidiSendThread"), |
| 85 event_thread_("MidiEventThread"), | 151 event_thread_("MidiEventThread"), |
| 86 event_thread_shutdown_(false) { | 152 event_thread_shutdown_(false) { |
| 87 // Initialize decoder. | 153 // Initialize decoder. |
| 88 snd_midi_event_new(0, &decoder_); | 154 snd_midi_event_new(0, &decoder_); |
| 89 snd_midi_event_no_status(decoder_, 1); | 155 snd_midi_event_no_status(decoder_, 1); |
| 90 } | 156 } |
| 91 | 157 |
| (...skipping 396 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 488 break; | 554 break; |
| 489 case MidiPort::Type::kOutput: | 555 case MidiPort::Type::kOutput: |
| 490 web_port_index = num_output_ports_++; | 556 web_port_index = num_output_ports_++; |
| 491 break; | 557 break; |
| 492 } | 558 } |
| 493 port->set_web_port_index(web_port_index); | 559 port->set_web_port_index(web_port_index); |
| 494 ports()->push_back(port.Pass()); | 560 ports()->push_back(port.Pass()); |
| 495 return web_port_index; | 561 return web_port_index; |
| 496 } | 562 } |
| 497 | 563 |
| 498 MidiManagerAlsa::AlsaSeqState::AlsaSeqState() : clients_deleter_(&clients_) { | 564 MidiManagerAlsa::AlsaSeqState::AlsaSeqState() |
| 565 : clients_deleter_(&clients_), card_client_count_(0) { |
| 499 } | 566 } |
| 500 | 567 |
| 501 MidiManagerAlsa::AlsaSeqState::~AlsaSeqState() { | 568 MidiManagerAlsa::AlsaSeqState::~AlsaSeqState() { |
| 502 } | 569 } |
| 503 | 570 |
| 504 void MidiManagerAlsa::AlsaSeqState::ClientStart(int client_id, | 571 void MidiManagerAlsa::AlsaSeqState::ClientStart(int client_id, |
| 505 const std::string& client_name, | 572 const std::string& client_name, |
| 506 snd_seq_client_type_t type) { | 573 snd_seq_client_type_t type) { |
| 507 ClientExit(client_id); | 574 ClientExit(client_id); |
| 508 clients_[client_id] = new Client(client_name, type); | 575 clients_[client_id] = new Client(client_name, type); |
| 576 if (IsCardClient(type, client_id)) |
| 577 ++card_client_count_; |
| 509 } | 578 } |
| 510 | 579 |
| 511 bool MidiManagerAlsa::AlsaSeqState::ClientStarted(int client_id) { | 580 bool MidiManagerAlsa::AlsaSeqState::ClientStarted(int client_id) { |
| 512 return clients_.find(client_id) != clients_.end(); | 581 return clients_.find(client_id) != clients_.end(); |
| 513 } | 582 } |
| 514 | 583 |
| 515 void MidiManagerAlsa::AlsaSeqState::ClientExit(int client_id) { | 584 void MidiManagerAlsa::AlsaSeqState::ClientExit(int client_id) { |
| 516 auto it = clients_.find(client_id); | 585 auto it = clients_.find(client_id); |
| 517 if (it != clients_.end()) { | 586 if (it != clients_.end()) { |
| 587 if (IsCardClient(it->second->type(), client_id)) |
| 588 --card_client_count_; |
| 518 delete it->second; | 589 delete it->second; |
| 519 clients_.erase(it); | 590 clients_.erase(it); |
| 520 } | 591 } |
| 521 } | 592 } |
| 522 | 593 |
| 523 void MidiManagerAlsa::AlsaSeqState::PortStart( | 594 void MidiManagerAlsa::AlsaSeqState::PortStart( |
| 524 int client_id, | 595 int client_id, |
| 525 int port_id, | 596 int port_id, |
| 526 const std::string& port_name, | 597 const std::string& port_name, |
| 527 MidiManagerAlsa::AlsaSeqState::PortDirection direction, | 598 MidiManagerAlsa::AlsaSeqState::PortDirection direction, |
| (...skipping 12 matching lines...) Expand all Loading... |
| 540 | 611 |
| 541 snd_seq_client_type_t MidiManagerAlsa::AlsaSeqState::ClientType( | 612 snd_seq_client_type_t MidiManagerAlsa::AlsaSeqState::ClientType( |
| 542 int client_id) const { | 613 int client_id) const { |
| 543 auto it = clients_.find(client_id); | 614 auto it = clients_.find(client_id); |
| 544 if (it == clients_.end()) | 615 if (it == clients_.end()) |
| 545 return SND_SEQ_USER_CLIENT; | 616 return SND_SEQ_USER_CLIENT; |
| 546 return it->second->type(); | 617 return it->second->type(); |
| 547 } | 618 } |
| 548 | 619 |
| 549 scoped_ptr<MidiManagerAlsa::TemporaryMidiPortState> | 620 scoped_ptr<MidiManagerAlsa::TemporaryMidiPortState> |
| 550 MidiManagerAlsa::AlsaSeqState::ToMidiPortState() { | 621 MidiManagerAlsa::AlsaSeqState::ToMidiPortState(const AlsaCardMap& alsa_cards) { |
| 551 scoped_ptr<MidiManagerAlsa::TemporaryMidiPortState> midi_ports( | 622 scoped_ptr<MidiManagerAlsa::TemporaryMidiPortState> midi_ports( |
| 552 new TemporaryMidiPortState); | 623 new TemporaryMidiPortState); |
| 553 // TODO(agoode): Use information from udev as well. | 624 // TODO(agoode): Use more information from udev, to allow hardware matching. |
| 625 // See http://crbug.com/486471. |
| 626 auto card_it = alsa_cards.begin(); |
| 554 | 627 |
| 628 int card_midi_device = -1; |
| 555 for (const auto& client_pair : clients_) { | 629 for (const auto& client_pair : clients_) { |
| 556 int client_id = client_pair.first; | 630 int client_id = client_pair.first; |
| 557 const auto& client = client_pair.second; | 631 const auto& client = client_pair.second; |
| 558 | 632 |
| 559 // Get client metadata. | 633 // Get client metadata. |
| 560 const std::string client_name = client->name(); | 634 const std::string client_name = client->name(); |
| 561 std::string manufacturer; | 635 std::string manufacturer; |
| 562 std::string driver; | 636 std::string driver; |
| 563 std::string path; | 637 std::string path; |
| 564 std::string id; | 638 std::string id; |
| 565 std::string serial; | 639 std::string serial; |
| 566 std::string card_name; | 640 std::string card_name; |
| 567 std::string card_longname; | 641 std::string card_longname; |
| 568 int midi_device = -1; | 642 int midi_device = -1; |
| 569 | 643 |
| 644 if (IsCardClient(client->type(), client_id)) { |
| 645 auto& card = card_it->second; |
| 646 if (card_midi_device == -1) |
| 647 card_midi_device = 0; |
| 648 |
| 649 manufacturer = card->manufacturer(); |
| 650 midi_device = card_midi_device; |
| 651 |
| 652 ++card_midi_device; |
| 653 if (card_midi_device >= card->midi_device_count()) { |
| 654 card_midi_device = -1; |
| 655 ++card_it; |
| 656 } |
| 657 } |
| 658 |
| 570 for (const auto& port_pair : *client) { | 659 for (const auto& port_pair : *client) { |
| 571 int port_id = port_pair.first; | 660 int port_id = port_pair.first; |
| 572 const auto& port = port_pair.second; | 661 const auto& port = port_pair.second; |
| 573 | 662 |
| 574 if (port->midi()) { | 663 if (port->midi()) { |
| 575 std::string version; | 664 std::string version; |
| 576 if (!driver.empty()) { | 665 if (!driver.empty()) { |
| 577 version = driver + " / "; | 666 version = driver + " / "; |
| 578 } | 667 } |
| 579 version += | 668 version += |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 655 MidiManagerAlsa::AlsaSeqState::Client::PortMap::const_iterator | 744 MidiManagerAlsa::AlsaSeqState::Client::PortMap::const_iterator |
| 656 MidiManagerAlsa::AlsaSeqState::Client::begin() const { | 745 MidiManagerAlsa::AlsaSeqState::Client::begin() const { |
| 657 return ports_.begin(); | 746 return ports_.begin(); |
| 658 } | 747 } |
| 659 | 748 |
| 660 MidiManagerAlsa::AlsaSeqState::Client::PortMap::const_iterator | 749 MidiManagerAlsa::AlsaSeqState::Client::PortMap::const_iterator |
| 661 MidiManagerAlsa::AlsaSeqState::Client::end() const { | 750 MidiManagerAlsa::AlsaSeqState::Client::end() const { |
| 662 return ports_.end(); | 751 return ports_.end(); |
| 663 } | 752 } |
| 664 | 753 |
| 754 MidiManagerAlsa::AlsaCard::AlsaCard(udev_device* dev, |
| 755 const std::string& alsa_name, |
| 756 const std::string& alsa_longname, |
| 757 const std::string& alsa_driver, |
| 758 int midi_device_count) |
| 759 : alsa_name_(alsa_name), |
| 760 alsa_longname_(alsa_longname), |
| 761 alsa_driver_(alsa_driver), |
| 762 midi_device_count_(midi_device_count) { |
| 763 // Try to get the vendor string. Sometimes it is encoded. |
| 764 std::string vendor = device::UdevDecodeString( |
| 765 device::UdevDeviceGetPropertyValue(dev, kUdevIdVendorEnc)); |
| 766 // Sometimes it is not encoded. |
| 767 if (vendor.empty()) |
| 768 vendor = |
| 769 UdevDeviceGetPropertyOrSysattr(dev, kUdevIdVendor, kSysattrVendorName); |
| 770 // Also get the vendor string from the hardware database. |
| 771 std::string vendor_from_database = |
| 772 device::UdevDeviceGetPropertyValue(dev, kUdevIdVendorFromDatabase); |
| 773 |
| 774 // Get the device path. |
| 775 path_ = device::UdevDeviceGetPropertyValue(dev, kUdevIdPath); |
| 776 // Get the bus. |
| 777 bus_ = device::UdevDeviceGetPropertyValue(dev, kUdevIdBus); |
| 778 |
| 779 // Get the "serial" number. (Often untrustable or missing.) |
| 780 serial_ = |
| 781 UdevDeviceGetPropertyOrSysattr(dev, kUdevIdSerialShort, kSysattrGuid); |
| 782 |
| 783 // Get the vendor id, by either property or sysattr. |
| 784 vendor_id_ = |
| 785 UdevDeviceGetPropertyOrSysattr(dev, kUdevIdVendorId, kSysattrVendor); |
| 786 // Get the model id, by either property or sysattr. |
| 787 model_id_ = |
| 788 UdevDeviceGetPropertyOrSysattr(dev, kUdevIdModelId, kSysattrModel); |
| 789 // Get the usb interface number. |
| 790 usb_interface_num_ = |
| 791 device::UdevDeviceGetPropertyValue(dev, kUdevIdUsbInterfaceNum); |
| 792 manufacturer_ = ExtractManufacturerString( |
| 793 vendor, vendor_id_, vendor_from_database, alsa_name, alsa_longname); |
| 794 } |
| 795 |
| 796 MidiManagerAlsa::AlsaCard::~AlsaCard() { |
| 797 } |
| 798 |
| 665 // static | 799 // static |
| 666 std::string MidiManagerAlsa::ExtractManufacturerString( | 800 std::string MidiManagerAlsa::AlsaCard::ExtractManufacturerString( |
| 667 const std::string& udev_id_vendor, | 801 const std::string& udev_id_vendor, |
| 668 const std::string& udev_id_vendor_id, | 802 const std::string& udev_id_vendor_id, |
| 669 const std::string& udev_id_vendor_from_database, | 803 const std::string& udev_id_vendor_from_database, |
| 670 const std::string& alsa_name, | 804 const std::string& alsa_name, |
| 671 const std::string& alsa_longname) { | 805 const std::string& alsa_longname) { |
| 672 // Let's try to determine the manufacturer. Here is the ordered preference | 806 // Let's try to determine the manufacturer. Here is the ordered preference |
| 673 // in extraction: | 807 // in extraction: |
| 674 // 1. Vendor name from the hardware device string, from udev properties | 808 // 1. Vendor name from the hardware device string, from udev properties |
| 675 // or sysattrs. | 809 // or sysattrs. |
| 676 // 2. Vendor name from the udev database (property ID_VENDOR_FROM_DATABASE). | 810 // 2. Vendor name from the udev database (property ID_VENDOR_FROM_DATABASE). |
| (...skipping 239 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 916 kUdevPropertySoundInitialized)) | 1050 kUdevPropertySoundInitialized)) |
| 917 return; | 1051 return; |
| 918 | 1052 |
| 919 // Get the action. If no action, then we are doing first time enumeration | 1053 // Get the action. If no action, then we are doing first time enumeration |
| 920 // and the device is treated as new. | 1054 // and the device is treated as new. |
| 921 const char* action = device::udev_device_get_action(dev); | 1055 const char* action = device::udev_device_get_action(dev); |
| 922 if (!action) | 1056 if (!action) |
| 923 action = kUdevActionChange; | 1057 action = kUdevActionChange; |
| 924 | 1058 |
| 925 if (strcmp(action, kUdevActionChange) == 0) { | 1059 if (strcmp(action, kUdevActionChange) == 0) { |
| 926 // TODO(agoode): add | 1060 AddCard(dev); |
| 1061 // Generate Web MIDI events. |
| 1062 UpdatePortStateAndGenerateEvents(); |
| 927 } else if (strcmp(action, kUdevActionRemove) == 0) { | 1063 } else if (strcmp(action, kUdevActionRemove) == 0) { |
| 928 // TODO(agoode): remove | 1064 RemoveCard(GetCardNumber(dev)); |
| 1065 // Generate Web MIDI events. |
| 1066 UpdatePortStateAndGenerateEvents(); |
| 929 } | 1067 } |
| 930 } | 1068 } |
| 931 | 1069 |
| 1070 void MidiManagerAlsa::AddCard(udev_device* dev) { |
| 1071 int number = GetCardNumber(dev); |
| 1072 if (number == -1) |
| 1073 return; |
| 1074 |
| 1075 RemoveCard(number); |
| 1076 |
| 1077 snd_ctl_card_info_t* card; |
| 1078 snd_hwdep_info_t* hwdep; |
| 1079 snd_ctl_card_info_alloca(&card); |
| 1080 snd_hwdep_info_alloca(&hwdep); |
| 1081 const std::string id = base::StringPrintf("hw:CARD=%i", number); |
| 1082 snd_ctl_t* handle; |
| 1083 int err = snd_ctl_open(&handle, id.c_str(), 0); |
| 1084 if (err != 0) { |
| 1085 VLOG(1) << "snd_ctl_open fails: " << snd_strerror(err); |
| 1086 return; |
| 1087 } |
| 1088 err = snd_ctl_card_info(handle, card); |
| 1089 if (err != 0) { |
| 1090 VLOG(1) << "snd_ctl_card_info fails: " << snd_strerror(err); |
| 1091 snd_ctl_close(handle); |
| 1092 return; |
| 1093 } |
| 1094 std::string name = snd_ctl_card_info_get_name(card); |
| 1095 std::string longname = snd_ctl_card_info_get_longname(card); |
| 1096 std::string driver = snd_ctl_card_info_get_driver(card); |
| 1097 |
| 1098 // Count rawmidi devices (not subdevices). |
| 1099 int midi_count = 0; |
| 1100 for (int device = -1; |
| 1101 !snd_ctl_rawmidi_next_device(handle, &device) && device >= 0;) |
| 1102 ++midi_count; |
| 1103 |
| 1104 // Count any hwdep synths that become MIDI devices outside of rawmidi. |
| 1105 // |
| 1106 // Explanation: |
| 1107 // Any kernel driver can create an ALSA client (visible to us). |
| 1108 // With modern hardware, only rawmidi devices do this. Kernel |
| 1109 // drivers create rawmidi devices and the rawmidi subsystem makes |
| 1110 // the seq clients. But the OPL3 driver is special, it does not |
| 1111 // make a rawmidi device but a seq client directly. (This is the |
| 1112 // only one to worry about in the kernel code, as of 2015-03-23.) |
| 1113 // |
| 1114 // OPL3 is very old (but still possible to get in new |
| 1115 // hardware). It is unlikely that new drivers would not use |
| 1116 // rawmidi and defeat our heuristic. |
| 1117 // |
| 1118 // Longer term, support should be added in the kernel to expose a |
| 1119 // direct link from card->client (or client->card) so that all |
| 1120 // these heuristics will be obsolete. Once that is there, we can |
| 1121 // assume our old heuristics will work on old kernels and the new |
| 1122 // robust code will be used on new. Then we will not need to worry |
| 1123 // about changes to kernel internals breaking our code. |
| 1124 // See the TODO above at kMinimumClientIdForCards. |
| 1125 for (int device = -1; |
| 1126 !snd_ctl_hwdep_next_device(handle, &device) && device >= 0;) { |
| 1127 err = snd_ctl_hwdep_info(handle, hwdep); |
| 1128 if (err != 0) { |
| 1129 VLOG(1) << "snd_ctl_hwdep_info fails: " << snd_strerror(err); |
| 1130 continue; |
| 1131 } |
| 1132 snd_hwdep_iface_t iface = snd_hwdep_info_get_iface(hwdep); |
| 1133 if (iface == SND_HWDEP_IFACE_OPL2 || iface == SND_HWDEP_IFACE_OPL3 || |
| 1134 iface == SND_HWDEP_IFACE_OPL4) |
| 1135 ++midi_count; |
| 1136 } |
| 1137 snd_ctl_close(handle); |
| 1138 |
| 1139 if (midi_count > 0) |
| 1140 alsa_cards_[number] = new AlsaCard(dev, name, longname, driver, midi_count); |
| 1141 alsa_card_midi_count_ += midi_count; |
| 1142 } |
| 1143 |
| 1144 void MidiManagerAlsa::RemoveCard(int number) { |
| 1145 auto it = alsa_cards_.find(number); |
| 1146 if (it == alsa_cards_.end()) |
| 1147 return; |
| 1148 |
| 1149 alsa_card_midi_count_ -= it->second->midi_device_count(); |
| 1150 delete it->second; |
| 1151 alsa_cards_.erase(it); |
| 1152 } |
| 1153 |
| 932 void MidiManagerAlsa::UpdatePortStateAndGenerateEvents() { | 1154 void MidiManagerAlsa::UpdatePortStateAndGenerateEvents() { |
| 1155 // Verify that our information from ALSA and udev are in sync. If |
| 1156 // not, we cannot generate events right now. |
| 1157 if (alsa_card_midi_count_ != alsa_seq_state_.card_client_count()) |
| 1158 return; |
| 1159 |
| 933 // Generate new port state. | 1160 // Generate new port state. |
| 934 auto new_port_state = alsa_seq_state_.ToMidiPortState(); | 1161 auto new_port_state = alsa_seq_state_.ToMidiPortState(alsa_cards_); |
| 935 | 1162 |
| 936 // Disconnect any connected old ports that are now missing. | 1163 // Disconnect any connected old ports that are now missing. |
| 937 for (auto* old_port : port_state_) { | 1164 for (auto* old_port : port_state_) { |
| 938 if (old_port->connected() && | 1165 if (old_port->connected() && |
| 939 (new_port_state->FindConnected(*old_port) == new_port_state->end())) { | 1166 (new_port_state->FindConnected(*old_port) == new_port_state->end())) { |
| 940 old_port->set_connected(false); | 1167 old_port->set_connected(false); |
| 941 uint32 web_port_index = old_port->web_port_index(); | 1168 uint32 web_port_index = old_port->web_port_index(); |
| 942 switch (old_port->type()) { | 1169 switch (old_port->type()) { |
| 943 case MidiPort::Type::kInput: | 1170 case MidiPort::Type::kInput: |
| 944 source_map_.erase( | 1171 source_map_.erase( |
| (...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1132 source_map_[AddrToInt(client_id, port_id)] = port_index; | 1359 source_map_[AddrToInt(client_id, port_id)] = port_index; |
| 1133 return true; | 1360 return true; |
| 1134 } | 1361 } |
| 1135 | 1362 |
| 1136 MidiManager* MidiManager::Create() { | 1363 MidiManager* MidiManager::Create() { |
| 1137 return new MidiManagerAlsa(); | 1364 return new MidiManagerAlsa(); |
| 1138 } | 1365 } |
| 1139 | 1366 |
| 1140 } // namespace midi | 1367 } // namespace midi |
| 1141 } // namespace media | 1368 } // namespace media |
| OLD | NEW |