Commit 774a30f2 authored by agoode's avatar agoode Committed by Commit bot

Web MIDI ALSA: Enable hardware based device matching

BUG=486471

Review URL: https://codereview.chromium.org/1145653002

Cr-Commit-Position: refs/heads/master@{#330941}
parent 558c1539
......@@ -124,6 +124,17 @@ int GetCardNumber(udev_device* dev) {
return number;
}
std::string GetVendor(udev_device* dev) {
// Try to get the vendor string. Sometimes it is encoded.
std::string vendor = device::UdevDecodeString(
device::UdevDeviceGetPropertyValue(dev, kUdevIdVendorEnc));
// Sometimes it is not encoded.
if (vendor.empty())
vendor =
UdevDeviceGetPropertyOrSysattr(dev, kUdevIdVendor, kSysattrVendorName);
return vendor;
}
void SetStringIfNonEmpty(base::DictionaryValue* value,
const std::string& path,
const std::string& in_value) {
......@@ -298,8 +309,38 @@ void MidiManagerAlsa::DispatchSendMidiData(MidiManagerClient* client,
base::Unretained(client), data.size()));
}
MidiManagerAlsa::MidiPort::Id::Id() = default;
MidiManagerAlsa::MidiPort::Id::Id(const std::string& bus,
const std::string& vendor_id,
const std::string& model_id,
const std::string& usb_interface_num,
const std::string& serial)
: bus_(bus),
vendor_id_(vendor_id),
model_id_(model_id),
usb_interface_num_(usb_interface_num),
serial_(serial) {
}
MidiManagerAlsa::MidiPort::Id::Id(const Id&) = default;
MidiManagerAlsa::MidiPort::Id::~Id() = default;
bool MidiManagerAlsa::MidiPort::Id::operator==(const Id& rhs) const {
return (bus_ == rhs.bus_) && (vendor_id_ == rhs.vendor_id_) &&
(model_id_ == rhs.model_id_) &&
(usb_interface_num_ == rhs.usb_interface_num_) &&
(serial_ == rhs.serial_);
}
bool MidiManagerAlsa::MidiPort::Id::empty() const {
return bus_.empty() && vendor_id_.empty() && model_id_.empty() &&
usb_interface_num_.empty() && serial_.empty();
}
MidiManagerAlsa::MidiPort::MidiPort(const std::string& path,
const std::string& id,
const Id& id,
int client_id,
int port_id,
int midi_device,
......@@ -339,13 +380,19 @@ scoped_ptr<base::Value> MidiManagerAlsa::MidiPort::Value() const {
}
value->SetString("type", type);
SetStringIfNonEmpty(value.get(), "path", path_);
SetStringIfNonEmpty(value.get(), "id", id_);
SetStringIfNonEmpty(value.get(), "clientName", client_name_);
SetStringIfNonEmpty(value.get(), "portName", port_name_);
value->SetInteger("clientId", client_id_);
value->SetInteger("portId", port_id_);
value->SetInteger("midiDevice", midi_device_);
// Flatten id fields.
SetStringIfNonEmpty(value.get(), "bus", id_.bus());
SetStringIfNonEmpty(value.get(), "vendorId", id_.vendor_id());
SetStringIfNonEmpty(value.get(), "modelId", id_.model_id());
SetStringIfNonEmpty(value.get(), "usbInterfaceNum", id_.usb_interface_num());
SetStringIfNonEmpty(value.get(), "serial", id_.serial());
return value.Pass();
}
......@@ -621,8 +668,7 @@ MidiManagerAlsa::AlsaSeqState::ToMidiPortState(const AlsaCardMap& alsa_cards) {
std::string manufacturer;
std::string driver;
std::string path;
std::string id;
std::string serial;
MidiPort::Id id;
std::string card_name;
std::string card_longname;
int midi_device = -1;
......@@ -633,6 +679,11 @@ MidiManagerAlsa::AlsaSeqState::ToMidiPortState(const AlsaCardMap& alsa_cards) {
card_midi_device = 0;
manufacturer = card->manufacturer();
path = card->path();
id = MidiPort::Id(card->bus(), card->vendor_id(), card->model_id(),
card->usb_interface_num(), card->serial());
card_name = card->name();
card_longname = card->longname();
midi_device = card_midi_device;
++card_midi_device;
......@@ -715,45 +766,31 @@ MidiManagerAlsa::AlsaSeqState::Client::end() const {
}
MidiManagerAlsa::AlsaCard::AlsaCard(udev_device* dev,
const std::string& alsa_name,
const std::string& alsa_longname,
const std::string& alsa_driver,
const std::string& name,
const std::string& longname,
const std::string& driver,
int midi_device_count)
: alsa_name_(alsa_name),
alsa_longname_(alsa_longname),
alsa_driver_(alsa_driver),
midi_device_count_(midi_device_count) {
// Try to get the vendor string. Sometimes it is encoded.
std::string vendor = device::UdevDecodeString(
device::UdevDeviceGetPropertyValue(dev, kUdevIdVendorEnc));
// Sometimes it is not encoded.
if (vendor.empty())
vendor =
UdevDeviceGetPropertyOrSysattr(dev, kUdevIdVendor, kSysattrVendorName);
// Also get the vendor string from the hardware database.
std::string vendor_from_database =
device::UdevDeviceGetPropertyValue(dev, kUdevIdVendorFromDatabase);
// Get the device path.
path_ = device::UdevDeviceGetPropertyValue(dev, kUdevIdPath);
// Get the bus.
bus_ = device::UdevDeviceGetPropertyValue(dev, kUdevIdBus);
// Get the "serial" number. (Often untrustable or missing.)
serial_ =
UdevDeviceGetPropertyOrSysattr(dev, kUdevIdSerialShort, kSysattrGuid);
// Get the vendor id, by either property or sysattr.
vendor_id_ =
UdevDeviceGetPropertyOrSysattr(dev, kUdevIdVendorId, kSysattrVendor);
// Get the model id, by either property or sysattr.
model_id_ =
UdevDeviceGetPropertyOrSysattr(dev, kUdevIdModelId, kSysattrModel);
// Get the usb interface number.
usb_interface_num_ =
device::UdevDeviceGetPropertyValue(dev, kUdevIdUsbInterfaceNum);
manufacturer_ = ExtractManufacturerString(
vendor, vendor_id_, vendor_from_database, alsa_name, alsa_longname);
: name_(name),
longname_(longname),
driver_(driver),
path_(device::UdevDeviceGetPropertyValue(dev, kUdevIdPath)),
bus_(device::UdevDeviceGetPropertyValue(dev, kUdevIdBus)),
vendor_id_(
UdevDeviceGetPropertyOrSysattr(dev, kUdevIdVendorId, kSysattrVendor)),
model_id_(
UdevDeviceGetPropertyOrSysattr(dev, kUdevIdModelId, kSysattrModel)),
usb_interface_num_(
device::UdevDeviceGetPropertyValue(dev, kUdevIdUsbInterfaceNum)),
serial_(UdevDeviceGetPropertyOrSysattr(dev,
kUdevIdSerialShort,
kSysattrGuid)),
midi_device_count_(midi_device_count),
manufacturer_(ExtractManufacturerString(
GetVendor(dev),
vendor_id_,
device::UdevDeviceGetPropertyValue(dev, kUdevIdVendorFromDatabase),
name,
longname)) {
}
MidiManagerAlsa::AlsaCard::~AlsaCard() = default;
......
......@@ -48,8 +48,40 @@ class MIDI_EXPORT MidiManagerAlsa final : public MidiManager {
public:
enum class Type { kInput, kOutput };
// The Id class is used to keep the multiple strings separate
// but compare them all together for equality purposes.
// The individual strings that make up the Id can theoretically contain
// arbitrary characters, so unfortunately there is no simple way to
// concatenate them into a single string.
class Id final {
public:
Id();
Id(const std::string& bus,
const std::string& vendor_id,
const std::string& model_id,
const std::string& usb_interface_num,
const std::string& serial);
Id(const Id&);
~Id();
bool operator==(const Id&) const;
bool empty() const;
std::string bus() const { return bus_; }
std::string vendor_id() const { return vendor_id_; }
std::string model_id() const { return model_id_; }
std::string usb_interface_num() const { return usb_interface_num_; }
std::string serial() const { return serial_; }
private:
std::string bus_;
std::string vendor_id_;
std::string model_id_;
std::string usb_interface_num_;
std::string serial_;
};
MidiPort(const std::string& path,
const std::string& id,
const Id& id,
int client_id,
int port_id,
int midi_device,
......@@ -84,7 +116,7 @@ class MIDI_EXPORT MidiManagerAlsa final : public MidiManager {
// accessors
std::string path() const { return path_; }
std::string id() const { return id_; }
Id id() const { return id_; }
std::string client_name() const { return client_name_; }
std::string port_name() const { return port_name_; }
std::string manufacturer() const { return manufacturer_; }
......@@ -119,7 +151,7 @@ class MIDI_EXPORT MidiManagerAlsa final : public MidiManager {
private:
// Immutable properties.
const std::string id_;
const Id id_;
const int midi_device_;
const Type type_;
......@@ -277,21 +309,22 @@ class MIDI_EXPORT MidiManagerAlsa final : public MidiManager {
class AlsaCard {
public:
AlsaCard(udev_device* dev,
const std::string& alsa_name,
const std::string& alsa_longname,
const std::string& alsa_driver,
const std::string& name,
const std::string& longname,
const std::string& driver,
int midi_device_count);
~AlsaCard();
const std::string alsa_name() const { return alsa_name_; }
const std::string alsa_longname() const { return alsa_longname_; }
const std::string manufacturer() const { return manufacturer_; }
const std::string alsa_driver() const { return alsa_driver_; }
std::string name() const { return name_; }
std::string longname() const { return longname_; }
std::string driver() const { return driver_; }
std::string path() const { return path_; }
std::string bus() const { return bus_; }
std::string vendor_id() const { return vendor_id_; }
std::string model_id() const { return model_id_; }
std::string usb_interface_num() const { return usb_interface_num_; }
std::string serial() const { return serial_; }
int midi_device_count() const { return midi_device_count_; }
// Returns hardware path.
const std::string path() const;
// Returns the id we can use to try to match hardware across different
// paths.
const std::string id() const;
std::string manufacturer() const { return manufacturer_; }
private:
FRIEND_TEST_ALL_PREFIXES(MidiManagerAlsaTest, ExtractManufacturer);
......@@ -301,20 +334,20 @@ class MIDI_EXPORT MidiManagerAlsa final : public MidiManager {
const std::string& udev_id_vendor,
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);
std::string alsa_name_;
std::string alsa_longname_;
std::string manufacturer_;
std::string alsa_driver_;
std::string path_;
std::string bus_;
std::string serial_;
std::string vendor_id_;
std::string model_id_;
std::string usb_interface_num_;
int midi_device_count_;
const std::string& name,
const std::string& longname);
const std::string name_;
const std::string longname_;
const std::string driver_;
const std::string path_;
const std::string bus_;
const std::string vendor_id_;
const std::string model_id_;
const std::string usb_interface_num_;
const std::string serial_;
const int midi_device_count_;
const std::string manufacturer_;
DISALLOW_COPY_AND_ASSIGN(AlsaCard);
};
......
......@@ -17,70 +17,99 @@ class MidiManagerAlsaTest : public ::testing::Test {
// Inputs. port_input_0_ == port_input_1_.
port_input_0_.reset(new MidiManagerAlsa::MidiPort(
"path", "id", 1, 2, 5, "client_name", "port_name", "manufacturer",
"version", MidiManagerAlsa::MidiPort::Type::kInput));
"path", MidiManagerAlsa::MidiPort::Id("bus", "vendor", "model",
"interface", "serial"),
1, 2, 5, "client_name", "port_name", "manufacturer", "version",
MidiManagerAlsa::MidiPort::Type::kInput));
port_input_1_.reset(new MidiManagerAlsa::MidiPort(
"path", "id", 1, 2, 5, "client_name", "port_name", "manufacturer",
"version", MidiManagerAlsa::MidiPort::Type::kInput));
port_input_minimal_.reset(
new MidiManagerAlsa::MidiPort("", "", 0, 0, 0, "", "", "", "",
MidiManagerAlsa::MidiPort::Type::kInput));
"path", MidiManagerAlsa::MidiPort::Id("bus", "vendor", "model",
"interface", "serial"),
1, 2, 5, "client_name", "port_name", "manufacturer", "version",
MidiManagerAlsa::MidiPort::Type::kInput));
port_input_minimal_.reset(new MidiManagerAlsa::MidiPort(
"", MidiManagerAlsa::MidiPort::Id(), 0, 0, 0, "", "", "", "",
MidiManagerAlsa::MidiPort::Type::kInput));
// Outputs. port_output_0_ == port_output_1_.
port_output_0_.reset(new MidiManagerAlsa::MidiPort(
"path", "id", 1, 2, 5, "client_name", "port_name", "manufacturer",
"version", MidiManagerAlsa::MidiPort::Type::kOutput));
"path", MidiManagerAlsa::MidiPort::Id("bus", "vendor", "model",
"interface", "serial"),
1, 2, 5, "client_name", "port_name", "manufacturer", "version",
MidiManagerAlsa::MidiPort::Type::kOutput));
port_output_1_.reset(new MidiManagerAlsa::MidiPort(
"path", "id", 1, 2, 5, "client_name", "port_name", "manufacturer",
"version", MidiManagerAlsa::MidiPort::Type::kOutput));
"path", MidiManagerAlsa::MidiPort::Id("bus", "vendor", "model",
"interface", "serial"),
1, 2, 5, "client_name", "port_name", "manufacturer", "version",
MidiManagerAlsa::MidiPort::Type::kOutput));
// MidiPort fields that differ from port_input_0_ in a single way each time.
// Used for testing the Match* and Find* methods.
port_input_0_alt_path_.reset(new MidiManagerAlsa::MidiPort(
"path2", "id", 1, 2, 5, "client_name", "port_name", "manufacturer",
"version", MidiManagerAlsa::MidiPort::Type::kInput));
"path2", MidiManagerAlsa::MidiPort::Id("bus", "vendor", "model",
"interface", "serial"),
1, 2, 5, "client_name", "port_name", "manufacturer", "version",
MidiManagerAlsa::MidiPort::Type::kInput));
port_input_0_alt_id_.reset(new MidiManagerAlsa::MidiPort(
"path", "id2", 1, 2, 5, "client_name", "port_name", "manufacturer",
"version", MidiManagerAlsa::MidiPort::Type::kInput));
"path", MidiManagerAlsa::MidiPort::Id("bus", "vendor", "model",
"interface", "serial2"),
1, 2, 5, "client_name", "port_name", "manufacturer", "version",
MidiManagerAlsa::MidiPort::Type::kInput));
port_input_0_alt_client_name_.reset(new MidiManagerAlsa::MidiPort(
"path", "id", 1, 2, 5, "client_name2", "port_name", "manufacturer",
"version", MidiManagerAlsa::MidiPort::Type::kInput));
"path", MidiManagerAlsa::MidiPort::Id("bus", "vendor", "model",
"interface", "serial"),
1, 2, 5, "client_name2", "port_name", "manufacturer", "version",
MidiManagerAlsa::MidiPort::Type::kInput));
port_input_0_alt_port_name_.reset(new MidiManagerAlsa::MidiPort(
"path", "id", 1, 2, 5, "client_name", "port_name2", "manufacturer",
"version", MidiManagerAlsa::MidiPort::Type::kInput));
"path", MidiManagerAlsa::MidiPort::Id("bus", "vendor", "model",
"interface", "serial"),
1, 2, 5, "client_name", "port_name2", "manufacturer", "version",
MidiManagerAlsa::MidiPort::Type::kInput));
port_input_0_alt_client_id_.reset(new MidiManagerAlsa::MidiPort(
"path", "id", 2, 2, 5, "client_name", "port_name", "manufacturer",
"version", MidiManagerAlsa::MidiPort::Type::kInput));
"path", MidiManagerAlsa::MidiPort::Id("bus", "vendor", "model",
"interface", "serial"),
2, 2, 5, "client_name", "port_name", "manufacturer", "version",
MidiManagerAlsa::MidiPort::Type::kInput));
port_input_0_alt_port_id_.reset(new MidiManagerAlsa::MidiPort(
"path", "id", 1, 3, 5, "client_name", "port_name", "manufacturer",
"version", MidiManagerAlsa::MidiPort::Type::kInput));
"path", MidiManagerAlsa::MidiPort::Id("bus", "vendor", "model",
"interface", "serial"),
1, 3, 5, "client_name", "port_name", "manufacturer", "version",
MidiManagerAlsa::MidiPort::Type::kInput));
port_input_0_alt_midi_device_.reset(new MidiManagerAlsa::MidiPort(
"path", "id", 1, 2, 6, "client_name", "port_name", "manufacturer",
"version", MidiManagerAlsa::MidiPort::Type::kInput));
"path", MidiManagerAlsa::MidiPort::Id("bus", "vendor", "model",
"interface", "serial"),
1, 2, 6, "client_name", "port_name", "manufacturer", "version",
MidiManagerAlsa::MidiPort::Type::kInput));
// "No card" variants of above. For testing FindDisconnected.
port_input_0_no_card_.reset(new MidiManagerAlsa::MidiPort(
"", "", 1, 2, -1, "client_name", "port_name", "manufacturer", "version",
"", MidiManagerAlsa::MidiPort::Id(), 1, 2, -1, "client_name",
"port_name", "manufacturer", "version",
MidiManagerAlsa::MidiPort::Type::kInput));
port_input_1_no_card_.reset(new MidiManagerAlsa::MidiPort(
"", "", 1, 2, -1, "client_name", "port_name", "manufacturer", "version",
"", MidiManagerAlsa::MidiPort::Id(), 1, 2, -1, "client_name",
"port_name", "manufacturer", "version",
MidiManagerAlsa::MidiPort::Type::kInput));
port_output_0_no_card_.reset(new MidiManagerAlsa::MidiPort(
"", "", 1, 2, -1, "client_name", "port_name", "manufacturer", "version",
"", MidiManagerAlsa::MidiPort::Id(), 1, 2, -1, "client_name",
"port_name", "manufacturer", "version",
MidiManagerAlsa::MidiPort::Type::kOutput));
// No card variants of the alt variants from above. For more testing
// of Match* and Find*.
port_input_0_no_card_alt_client_name_.reset(new MidiManagerAlsa::MidiPort(
"", "", 1, 2, -1, "client_name2", "port_name", "manufacturer",
"version", MidiManagerAlsa::MidiPort::Type::kInput));
"", MidiManagerAlsa::MidiPort::Id(), 1, 2, -1, "client_name2",
"port_name", "manufacturer", "version",
MidiManagerAlsa::MidiPort::Type::kInput));
port_input_0_no_card_alt_port_name_.reset(new MidiManagerAlsa::MidiPort(
"", "", 1, 2, -1, "client_name", "port_name2", "manufacturer",
"version", MidiManagerAlsa::MidiPort::Type::kInput));
"", MidiManagerAlsa::MidiPort::Id(), 1, 2, -1, "client_name",
"port_name2", "manufacturer", "version",
MidiManagerAlsa::MidiPort::Type::kInput));
port_input_0_no_card_alt_client_id_.reset(new MidiManagerAlsa::MidiPort(
"", "", 2, 2, -1, "client_name", "port_name", "manufacturer", "version",
"", MidiManagerAlsa::MidiPort::Id(), 2, 2, -1, "client_name",
"port_name", "manufacturer", "version",
MidiManagerAlsa::MidiPort::Type::kInput));
port_input_0_no_card_alt_port_id_.reset(new MidiManagerAlsa::MidiPort(
"", "", 1, 3, -1, "client_name", "port_name", "manufacturer", "version",
"", MidiManagerAlsa::MidiPort::Id(), 1, 3, -1, "client_name",
"port_name", "manufacturer", "version",
MidiManagerAlsa::MidiPort::Type::kInput));
}
......@@ -180,20 +209,22 @@ TEST_F(MidiManagerAlsaTest, ExtractManufacturer) {
// MidiPort.
TEST_F(MidiManagerAlsaTest, JSONPortMetadata) {
EXPECT_EQ(
"{\"clientId\":1,\"clientName\":\"client_name\",\"id\":\"id\","
"\"midiDevice\":5,\"path\":\"path\",\"portId\":2,\"portName\":\"port_"
"name\",\"type\":\"input\"}",
"{\"bus\":\"bus\",\"clientId\":1,\"clientName\":\"client_name\","
"\"midiDevice\":5,\"modelId\":\"model\",\"path\":\"path\",\"portId\":2,"
"\"portName\":\"port_name\",\"serial\":\"serial\",\"type\":\"input\","
"\"usbInterfaceNum\":\"interface\",\"vendorId\":\"vendor\"}",
port_input_0_->JSONValue());
EXPECT_EQ("03F255B7EE4D9D061597289CB16B45F997DBDB20D8E44429B052019C84E20A4A",
EXPECT_EQ("810194DAF713B32FC9BE40EC822E21682635B48C242D09EA95DBA4A184A95877",
port_input_0_->OpaqueKey());
EXPECT_EQ(
"{\"clientId\":1,\"clientName\":\"client_name\",\"id\":\"id\","
"\"midiDevice\":5,\"path\":\"path\",\"portId\":2,\"portName\":\"port_"
"name\",\"type\":\"output\"}",
"{\"bus\":\"bus\",\"clientId\":1,\"clientName\":\"client_name\","
"\"midiDevice\":5,\"modelId\":\"model\",\"path\":\"path\",\"portId\":2,"
"\"portName\":\"port_name\",\"serial\":\"serial\",\"type\":\"output\","
"\"usbInterfaceNum\":\"interface\",\"vendorId\":\"vendor\"}",
port_output_0_->JSONValue());
EXPECT_EQ("3A3380FD64B8C79900C052D64C3F52E9ECD6537D00ECB02B8FA30032C0C03924",
EXPECT_EQ("C32552FC772A0CA453A675CED05EFB3BDEF749EB58ED9522475206F111BC01E2",
port_output_0_->OpaqueKey());
EXPECT_EQ("{\"clientId\":0,\"midiDevice\":0,\"portId\":0,\"type\":\"input\"}",
......@@ -605,8 +636,8 @@ TEST_F(MidiManagerAlsaTest, ToMidiPortState) {
// Verify the last entry.
EXPECT_TRUE((*alsa_seq_state_0_.ToMidiPortState(alsa_cards_)->begin())
->MatchConnected(MidiManagerAlsa::MidiPort(
"", "", 0, 1, -1, "0", "0:1", "", "",
MidiManagerAlsa::MidiPort::Type::kOutput)));
"", MidiManagerAlsa::MidiPort::Id(), 0, 1, -1, "0", "0:1",
"", "", MidiManagerAlsa::MidiPort::Type::kOutput)));
}
// Tests card_client_count of AlsaSeqState.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment