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 |