| 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/json/json_string_value_serializer.h" |
| 13 #include "base/logging.h" | 14 #include "base/logging.h" |
| 14 #include "base/memory/ref_counted.h" | 15 #include "base/memory/scoped_ptr.h" |
| 15 #include "base/memory/scoped_vector.h" | 16 #include "base/memory/scoped_vector.h" |
| 16 #include "base/message_loop/message_loop.h" | 17 #include "base/message_loop/message_loop.h" |
| 17 #include "base/posix/eintr_wrapper.h" | 18 #include "base/posix/eintr_wrapper.h" |
| 19 #include "base/strings/string_number_conversions.h" |
| 18 #include "base/strings/stringprintf.h" | 20 #include "base/strings/stringprintf.h" |
| 19 #include "base/threading/thread.h" | 21 #include "base/threading/thread.h" |
| 20 #include "base/time/time.h" | 22 #include "base/time/time.h" |
| 23 #include "base/values.h" |
| 24 #include "crypto/sha2.h" |
| 21 #include "media/midi/midi_port_info.h" | 25 #include "media/midi/midi_port_info.h" |
| 22 | 26 |
| 23 namespace media { | 27 namespace media { |
| 24 | 28 |
| 25 namespace { | 29 namespace { |
| 26 | 30 |
| 27 // Per-output buffer. This can be smaller, but then large sysex messages | 31 // Per-output buffer. This can be smaller, but then large sysex messages |
| 28 // will be (harmlessly) split across multiple seq events. This should | 32 // will be (harmlessly) split across multiple seq events. This should |
| 29 // not have any real practical effect, except perhaps to slightly reorder | 33 // not have any real practical effect, except perhaps to slightly reorder |
| 30 // realtime messages with respect to sysex. | 34 // realtime messages with respect to sysex. |
| 31 const size_t kSendBufferSize = 256; | 35 const size_t kSendBufferSize = 256; |
| 32 | 36 |
| 33 // Minimum client id for which we will have ALSA card devices for. When we | 37 // Minimum client id for which we will have ALSA card devices for. When we |
| 34 // are searching for card devices (used to get the path, id, and manufacturer), | 38 // are searching for card devices (used to get the path, id, and manufacturer), |
| 35 // we don't want to get confused by kernel clients that do not have a card. | 39 // we don't want to get confused by kernel clients that do not have a card. |
| 36 // See seq_clientmgr.c in the ALSA code for this. | 40 // See seq_clientmgr.c in the ALSA code for this. |
| 37 // TODO(agoode): Add proper client -> card export from the kernel to avoid | 41 // TODO(agoode): Add proper client -> card export from the kernel to avoid |
| 38 // hardcoding. | 42 // hardcoding. |
| 39 const int kMinimumClientIdForCards = 16; | 43 const int kMinimumClientIdForCards = 16; |
| 40 | 44 |
| 45 // udev key constants. |
| 46 const char kSoundClass[] = "sound"; |
| 47 const char kIdVendor[] = "ID_VENDOR"; |
| 48 const char kIdVendorEnc[] = "ID_VENDOR_ENC"; |
| 49 const char kIdVendorFromDatabase[] = "ID_VENDOR_FROM_DATABASE"; |
| 50 const char kSysattrVendorName[] = "vendor_name"; |
| 51 const char kIdVendorId[] = "ID_VENDOR_ID"; |
| 52 const char kSysattrVendor[] = "vendor"; |
| 53 const char kIdModelId[] = "ID_MODEL_ID"; |
| 54 const char kSysattrModel[] = "model"; |
| 55 const char kIdBus[] = "ID_BUS"; |
| 56 const char kIdPath[] = "ID_PATH"; |
| 57 const char kUsbInterfaceNum[] = "ID_USB_INTERFACE_NUM"; |
| 58 |
| 59 // ALSA constants. |
| 60 const char kAlsaHw[] = "hw"; |
| 61 |
| 41 // Constants for the capabilities we search for in inputs and outputs. | 62 // Constants for the capabilities we search for in inputs and outputs. |
| 42 // See http://www.alsa-project.org/alsa-doc/alsa-lib/seq.html. | 63 // See http://www.alsa-project.org/alsa-doc/alsa-lib/seq.html. |
| 43 const unsigned int kRequiredInputPortCaps = | 64 const unsigned int kRequiredInputPortCaps = |
| 44 SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_READ; | 65 SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_READ; |
| 45 const unsigned int kRequiredOutputPortCaps = | 66 const unsigned int kRequiredOutputPortCaps = |
| 46 SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE; | 67 SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE; |
| 47 | 68 |
| 48 int AddrToInt(const snd_seq_addr_t* addr) { | 69 int AddrToInt(const snd_seq_addr_t* addr) { |
| 49 return (addr->client << 8) | addr->port; | 70 return (addr->client << 8) | addr->port; |
| 50 } | 71 } |
| 51 | 72 |
| 73 // TODO(agoode): Move this to device/udev_linux. |
| 74 #if defined(USE_UDEV) |
| 75 const std::string UdevDeviceGetPropertyOrSysattr( |
| 76 struct udev_device* udev_device, |
| 77 const char* property_key, |
| 78 const char* sysattr_key) { |
| 79 // First try the property. |
| 80 std::string value = |
| 81 device::UdevDeviceGetPropertyValue(udev_device, property_key); |
| 82 |
| 83 // If no property, look for sysattrs and walk up the parent devices too. |
| 84 while (value.empty() && udev_device) { |
| 85 value = device::UdevDeviceGetSysattrValue(udev_device, sysattr_key); |
| 86 udev_device = device::udev_device_get_parent(udev_device); |
| 87 } |
| 88 return value; |
| 89 } |
| 90 #endif // defined(USE_UDEV) |
| 91 |
| 52 } // namespace | 92 } // namespace |
| 53 | 93 |
| 54 MidiManagerAlsa::MidiManagerAlsa() | 94 MidiManagerAlsa::MidiManagerAlsa() |
| 55 : in_client_(NULL), | 95 : in_client_(NULL), |
| 56 out_client_(NULL), | 96 out_client_(NULL), |
| 57 out_client_id_(-1), | 97 out_client_id_(-1), |
| 58 in_port_(-1), | 98 in_port_(-1), |
| 59 decoder_(NULL), | 99 decoder_(NULL), |
| 60 #if defined(USE_UDEV) | 100 #if defined(USE_UDEV) |
| 61 udev_(device::udev_new()), | 101 udev_(device::udev_new()), |
| (...skipping 25 matching lines...) Expand all Loading... |
| 87 | 127 |
| 88 // Wait for the event thread to stop. | 128 // Wait for the event thread to stop. |
| 89 event_thread_.Stop(); | 129 event_thread_.Stop(); |
| 90 | 130 |
| 91 // Close the in client. | 131 // Close the in client. |
| 92 if (in_client_) | 132 if (in_client_) |
| 93 snd_seq_close(in_client_); | 133 snd_seq_close(in_client_); |
| 94 | 134 |
| 95 // Free the decoder. | 135 // Free the decoder. |
| 96 snd_midi_event_free(decoder_); | 136 snd_midi_event_free(decoder_); |
| 97 | |
| 98 // Free the encoders. | |
| 99 for (EncoderList::iterator i = encoders_.begin(); i != encoders_.end(); ++i) | |
| 100 snd_midi_event_free(*i); | |
| 101 } | 137 } |
| 102 | 138 |
| 103 void MidiManagerAlsa::StartInitialization() { | 139 void MidiManagerAlsa::StartInitialization() { |
| 104 // TODO(agoode): Move off I/O thread. See http://crbug.com/374341. | 140 // TODO(agoode): Move off I/O thread. See http://crbug.com/374341. |
| 105 | 141 |
| 106 // Create client handles. | 142 // Create client handles. |
| 107 int err = snd_seq_open(&in_client_, "hw", SND_SEQ_OPEN_INPUT, 0); | 143 int err = snd_seq_open(&in_client_, kAlsaHw, SND_SEQ_OPEN_INPUT, 0); |
| 108 if (err != 0) { | 144 if (err != 0) { |
| 109 VLOG(1) << "snd_seq_open fails: " << snd_strerror(err); | 145 VLOG(1) << "snd_seq_open fails: " << snd_strerror(err); |
| 110 return CompleteInitialization(MIDI_INITIALIZATION_ERROR); | 146 return CompleteInitialization(MIDI_INITIALIZATION_ERROR); |
| 111 } | 147 } |
| 112 int in_client_id = snd_seq_client_id(in_client_); | 148 int in_client_id = snd_seq_client_id(in_client_); |
| 113 err = snd_seq_open(&out_client_, "hw", SND_SEQ_OPEN_OUTPUT, 0); | 149 err = snd_seq_open(&out_client_, kAlsaHw, SND_SEQ_OPEN_OUTPUT, 0); |
| 114 if (err != 0) { | 150 if (err != 0) { |
| 115 VLOG(1) << "snd_seq_open fails: " << snd_strerror(err); | 151 VLOG(1) << "snd_seq_open fails: " << snd_strerror(err); |
| 116 return CompleteInitialization(MIDI_INITIALIZATION_ERROR); | 152 return CompleteInitialization(MIDI_INITIALIZATION_ERROR); |
| 117 } | 153 } |
| 118 out_client_id_ = snd_seq_client_id(out_client_); | 154 out_client_id_ = snd_seq_client_id(out_client_); |
| 119 | 155 |
| 120 // Name the clients. | 156 // Name the clients. |
| 121 err = snd_seq_set_client_name(in_client_, "Chrome (input)"); | 157 err = snd_seq_set_client_name(in_client_, "Chrome (input)"); |
| 122 if (err != 0) { | 158 if (err != 0) { |
| 123 VLOG(1) << "snd_seq_set_client_name fails: " << snd_strerror(err); | 159 VLOG(1) << "snd_seq_set_client_name fails: " << snd_strerror(err); |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 191 FROM_HERE, base::Bind(&MidiManagerAlsa::SendMidiData, | 227 FROM_HERE, base::Bind(&MidiManagerAlsa::SendMidiData, |
| 192 base::Unretained(this), port_index, data), | 228 base::Unretained(this), port_index, data), |
| 193 delay); | 229 delay); |
| 194 | 230 |
| 195 // Acknowledge send. | 231 // Acknowledge send. |
| 196 send_thread_.message_loop()->PostTask( | 232 send_thread_.message_loop()->PostTask( |
| 197 FROM_HERE, base::Bind(&MidiManagerClient::AccumulateMidiBytesSent, | 233 FROM_HERE, base::Bind(&MidiManagerClient::AccumulateMidiBytesSent, |
| 198 base::Unretained(client), data.size())); | 234 base::Unretained(client), data.size())); |
| 199 } | 235 } |
| 200 | 236 |
| 201 MidiManagerAlsa::MidiDevice::MidiDevice(const MidiManagerAlsa* outer, | 237 MidiManagerAlsa::AlsaRawmidi::AlsaRawmidi(const MidiManagerAlsa* outer, |
| 202 const std::string& alsa_name, | 238 const std::string& alsa_name, |
| 203 const std::string& alsa_longname, | 239 const std::string& alsa_longname, |
| 204 const std::string& alsa_driver, | 240 const std::string& alsa_driver, |
| 205 int card_index) | 241 int card_index) |
| 206 : alsa_name_(alsa_name), alsa_driver_(alsa_driver) { | 242 : alsa_name_(alsa_name), |
| 243 alsa_longname_(alsa_longname), |
| 244 alsa_driver_(alsa_driver) { |
| 207 // Get udev properties if available. | 245 // Get udev properties if available. |
| 208 std::string udev_id_vendor; | 246 std::string vendor; |
| 209 std::string udev_id_vendor_id; | 247 std::string vendor_from_database; |
| 210 std::string udev_id_vendor_from_database; | |
| 211 | 248 |
| 212 #if defined(USE_UDEV) | 249 #if defined(USE_UDEV) |
| 213 const std::string sysname = base::StringPrintf("card%i", card_index); | 250 const std::string sysname = base::StringPrintf("card%i", card_index); |
| 214 device::ScopedUdevDevicePtr udev_device( | 251 device::ScopedUdevDevicePtr udev_device( |
| 215 device::udev_device_new_from_subsystem_sysname(outer->udev_.get(), | 252 device::udev_device_new_from_subsystem_sysname( |
| 216 "sound", sysname.c_str())); | 253 outer->udev_.get(), kSoundClass, sysname.c_str())); |
| 217 udev_id_vendor = device::UdevDecodeString( | |
| 218 device::UdevDeviceGetPropertyValue(udev_device.get(), "ID_VENDOR_ENC")); | |
| 219 udev_id_vendor_id = | |
| 220 device::UdevDeviceGetPropertyValue(udev_device.get(), "ID_VENDOR_ID"); | |
| 221 udev_id_vendor_from_database = device::UdevDeviceGetPropertyValue( | |
| 222 udev_device.get(), "ID_VENDOR_FROM_DATABASE"); | |
| 223 | 254 |
| 224 udev_id_path_ = | 255 // TODO(agoode): Move this to a new utility class in device/udev_linux? |
| 225 device::UdevDeviceGetPropertyValue(udev_device.get(), "ID_PATH"); | 256 |
| 226 udev_id_id_ = device::UdevDeviceGetPropertyValue(udev_device.get(), "ID_ID"); | 257 // Try to get the vendor string. Sometimes it is encoded. |
| 258 vendor = device::UdevDecodeString( |
| 259 device::UdevDeviceGetPropertyValue(udev_device.get(), kIdVendorEnc)); |
| 260 // Sometimes it is not encoded. |
| 261 if (vendor.empty()) |
| 262 UdevDeviceGetPropertyOrSysattr(udev_device.get(), kIdVendor, |
| 263 kSysattrVendorName); |
| 264 // Also get the vendor string from the hardware database. |
| 265 vendor_from_database = device::UdevDeviceGetPropertyValue( |
| 266 udev_device.get(), kIdVendorFromDatabase); |
| 267 |
| 268 // Get the device path. |
| 269 path_ = device::UdevDeviceGetPropertyValue(udev_device.get(), kIdPath); |
| 270 |
| 271 // Get the bus. |
| 272 bus_ = device::UdevDeviceGetPropertyValue(udev_device.get(), kIdBus); |
| 273 |
| 274 // Get the vendor id, by either property or sysattr. |
| 275 vendor_id_ = UdevDeviceGetPropertyOrSysattr(udev_device.get(), kIdVendorId, |
| 276 kSysattrVendor); |
| 277 |
| 278 // Get the model id, by either property or sysattr. |
| 279 model_id_ = UdevDeviceGetPropertyOrSysattr(udev_device.get(), kIdModelId, |
| 280 kSysattrModel); |
| 281 |
| 282 // Get the usb interface number. |
| 283 usb_interface_num_ = |
| 284 device::UdevDeviceGetPropertyValue(udev_device.get(), kUsbInterfaceNum); |
| 227 #endif // defined(USE_UDEV) | 285 #endif // defined(USE_UDEV) |
| 228 | 286 |
| 229 manufacturer_ = ExtractManufacturerString(udev_id_vendor, udev_id_vendor_id, | 287 manufacturer_ = ExtractManufacturerString( |
| 230 udev_id_vendor_from_database, | 288 vendor, vendor_id_, vendor_from_database, alsa_name, alsa_longname); |
| 231 alsa_name, alsa_longname); | |
| 232 } | 289 } |
| 233 | 290 |
| 234 MidiManagerAlsa::MidiDevice::~MidiDevice() { | 291 MidiManagerAlsa::AlsaRawmidi::~AlsaRawmidi() { |
| 235 } | 292 } |
| 236 | 293 |
| 237 const std::string MidiManagerAlsa::MidiDevice::alsa_name() const { | 294 const std::string MidiManagerAlsa::AlsaRawmidi::alsa_name() const { |
| 238 return alsa_name_; | 295 return alsa_name_; |
| 239 } | 296 } |
| 240 | 297 |
| 241 const std::string MidiManagerAlsa::MidiDevice::manufacturer() const { | 298 const std::string MidiManagerAlsa::AlsaRawmidi::alsa_longname() const { |
| 299 return alsa_longname_; |
| 300 } |
| 301 |
| 302 const std::string MidiManagerAlsa::AlsaRawmidi::manufacturer() const { |
| 242 return manufacturer_; | 303 return manufacturer_; |
| 243 } | 304 } |
| 244 | 305 |
| 245 const std::string MidiManagerAlsa::MidiDevice::alsa_driver() const { | 306 const std::string MidiManagerAlsa::AlsaRawmidi::alsa_driver() const { |
| 246 return alsa_driver_; | 307 return alsa_driver_; |
| 247 } | 308 } |
| 248 | 309 |
| 249 const std::string MidiManagerAlsa::MidiDevice::udev_id_path() const { | 310 const std::string MidiManagerAlsa::AlsaRawmidi::path() const { |
| 250 return udev_id_path_; | 311 return path_; |
| 251 } | 312 } |
| 252 | 313 |
| 253 const std::string MidiManagerAlsa::MidiDevice::udev_id_id() const { | 314 const std::string MidiManagerAlsa::AlsaRawmidi::bus() const { |
| 254 return udev_id_id_; | 315 return bus_; |
| 316 } |
| 317 |
| 318 const std::string MidiManagerAlsa::AlsaRawmidi::vendor_id() const { |
| 319 return vendor_id_; |
| 320 } |
| 321 |
| 322 const std::string MidiManagerAlsa::AlsaRawmidi::id() const { |
| 323 std::string id = vendor_id_; |
| 324 if (!model_id_.empty()) |
| 325 id += ":" + model_id_; |
| 326 if (!usb_interface_num_.empty()) |
| 327 id += ":" + usb_interface_num_; |
| 328 return id; |
| 255 } | 329 } |
| 256 | 330 |
| 257 // static | 331 // static |
| 258 std::string MidiManagerAlsa::MidiDevice::ExtractManufacturerString( | 332 std::string MidiManagerAlsa::AlsaRawmidi::ExtractManufacturerString( |
| 259 const std::string& udev_id_vendor, | 333 const std::string& udev_id_vendor, |
| 260 const std::string& udev_id_vendor_id, | 334 const std::string& udev_id_vendor_id, |
| 261 const std::string& udev_id_vendor_from_database, | 335 const std::string& udev_id_vendor_from_database, |
| 262 const std::string& alsa_name, | 336 const std::string& alsa_name, |
| 263 const std::string& alsa_longname) { | 337 const std::string& alsa_longname) { |
| 264 // Let's try to determine the manufacturer. Here is the ordered preference | 338 // Let's try to determine the manufacturer. Here is the ordered preference |
| 265 // in extraction: | 339 // in extraction: |
| 266 // 1. Vendor name from the USB device iManufacturer string, from | 340 // 1. Vendor name from the hardware device string, from udev properties |
| 267 // the udev property ID_VENDOR_ENC. | 341 // or sysattrs. |
| 268 // 2. Vendor name from the udev database (property ID_VENDOR_FROM_DATABASE). | 342 // 2. Vendor name from the udev database (property ID_VENDOR_FROM_DATABASE). |
| 269 // 3. Heuristic from ALSA. | 343 // 3. Heuristic from ALSA. |
| 270 | 344 |
| 271 // Is the vendor string not just the USB vendor hex id? | 345 // Is the vendor string not just the vendor hex id? |
| 272 if (udev_id_vendor != udev_id_vendor_id) { | 346 if (udev_id_vendor != udev_id_vendor_id) { |
| 273 return udev_id_vendor; | 347 return udev_id_vendor; |
| 274 } | 348 } |
| 275 | 349 |
| 276 // Is there a vendor string in the hardware database? | 350 // Is there a vendor string in the hardware database? |
| 277 if (!udev_id_vendor_from_database.empty()) { | 351 if (!udev_id_vendor_from_database.empty()) { |
| 278 return udev_id_vendor_from_database; | 352 return udev_id_vendor_from_database; |
| 279 } | 353 } |
| 280 | 354 |
| 281 // Ok, udev gave us nothing useful, or was unavailable. So try a heuristic. | 355 // Ok, udev gave us nothing useful, or was unavailable. So try a heuristic. |
| 282 // We assume that card longname is in the format of | 356 // We assume that card longname is in the format of |
| 283 // "<manufacturer> <name> at <bus>". Otherwise, we give up to detect | 357 // "<manufacturer> <name> at <bus>". Otherwise, we give up to detect |
| 284 // a manufacturer name here. | 358 // a manufacturer name here. |
| 285 size_t at_index = alsa_longname.rfind(" at "); | 359 size_t at_index = alsa_longname.rfind(" at "); |
| 286 if (std::string::npos != at_index) { | 360 if (at_index && at_index != std::string::npos) { |
| 287 size_t name_index = alsa_longname.rfind(alsa_name, at_index - 1); | 361 size_t name_index = alsa_longname.rfind(alsa_name, at_index - 1); |
| 288 if (std::string::npos != name_index) | 362 if (name_index && name_index != std::string::npos) |
| 289 return alsa_longname.substr(0, name_index - 1); | 363 return alsa_longname.substr(0, name_index - 1); |
| 290 } | 364 } |
| 291 | 365 |
| 292 // Failure. | 366 // Failure. |
| 293 return ""; | 367 return ""; |
| 294 } | 368 } |
| 295 | 369 |
| 296 ScopedVector<MidiManagerAlsa::MidiDevice> MidiManagerAlsa::AllMidiDevices() { | 370 MidiManagerAlsa::AlsaPortMetadata::AlsaPortMetadata( |
| 297 ScopedVector<MidiDevice> devices; | 371 const std::string& path, |
| 372 const std::string& bus, |
| 373 const std::string& id, |
| 374 const snd_seq_addr_t* address, |
| 375 const std::string& client_name, |
| 376 const std::string& port_name, |
| 377 const std::string& card_name, |
| 378 const std::string& card_longname, |
| 379 Type type) |
| 380 : path_(path), |
| 381 bus_(bus), |
| 382 id_(id), |
| 383 client_addr_(address->client), |
| 384 port_addr_(address->port), |
| 385 client_name_(client_name), |
| 386 port_name_(port_name), |
| 387 card_name_(card_name), |
| 388 card_longname_(card_longname), |
| 389 type_(type) { |
| 390 } |
| 391 |
| 392 MidiManagerAlsa::AlsaPortMetadata::~AlsaPortMetadata() { |
| 393 } |
| 394 |
| 395 scoped_ptr<base::Value> MidiManagerAlsa::AlsaPortMetadata::Value() const { |
| 396 base::DictionaryValue* value = new base::DictionaryValue(); |
| 397 value->SetString("path", path_); |
| 398 value->SetString("bus", bus_); |
| 399 value->SetString("id", id_); |
| 400 value->SetInteger("clientAddr", client_addr_); |
| 401 value->SetInteger("portAddr", port_addr_); |
| 402 value->SetString("clientName", client_name_); |
| 403 value->SetString("portName", port_name_); |
| 404 value->SetString("cardName", card_name_); |
| 405 value->SetString("cardLongname", card_longname_); |
| 406 std::string type; |
| 407 switch (type_) { |
| 408 case Type::kInput: |
| 409 type = "input"; |
| 410 break; |
| 411 |
| 412 case Type::kOutput: |
| 413 type = "output"; |
| 414 break; |
| 415 } |
| 416 value->SetString("type", type); |
| 417 |
| 418 return scoped_ptr<base::Value>(value).Pass(); |
| 419 } |
| 420 |
| 421 std::string MidiManagerAlsa::AlsaPortMetadata::JSONValue() const { |
| 422 std::string json; |
| 423 JSONStringValueSerializer serializer(&json); |
| 424 serializer.Serialize(*Value().get()); |
| 425 return json; |
| 426 } |
| 427 |
| 428 // TODO(agoode): Do not use SHA256 here. Instead store a persistent |
| 429 // mapping and just use a UUID or other random string. |
| 430 // http://crbug.com/465320 |
| 431 std::string MidiManagerAlsa::AlsaPortMetadata::OpaqueKey() const { |
| 432 uint8 hash[crypto::kSHA256Length]; |
| 433 crypto::SHA256HashString(JSONValue(), &hash, sizeof(hash)); |
| 434 return base::HexEncode(&hash, sizeof(hash)); |
| 435 } |
| 436 |
| 437 // TODO(agoode): Add a client->card/rawmidi mapping to the kernel to avoid |
| 438 // needing to probe in this way. |
| 439 ScopedVector<MidiManagerAlsa::AlsaRawmidi> MidiManagerAlsa::AllAlsaRawmidis() { |
| 440 ScopedVector<AlsaRawmidi> devices; |
| 298 snd_ctl_card_info_t* card; | 441 snd_ctl_card_info_t* card; |
| 299 snd_rawmidi_info_t* midi_out; | 442 snd_rawmidi_info_t* midi_out; |
| 300 snd_rawmidi_info_t* midi_in; | 443 snd_rawmidi_info_t* midi_in; |
| 301 snd_ctl_card_info_alloca(&card); | 444 snd_ctl_card_info_alloca(&card); |
| 302 snd_rawmidi_info_alloca(&midi_out); | 445 snd_rawmidi_info_alloca(&midi_out); |
| 303 snd_rawmidi_info_alloca(&midi_in); | 446 snd_rawmidi_info_alloca(&midi_in); |
| 304 for (int card_index = -1; !snd_card_next(&card_index) && card_index >= 0;) { | 447 for (int card_index = -1; !snd_card_next(&card_index) && card_index >= 0;) { |
| 305 const std::string id = base::StringPrintf("hw:CARD=%i", card_index); | 448 const std::string id = base::StringPrintf("hw:CARD=%i", card_index); |
| 306 snd_ctl_t* handle; | 449 snd_ctl_t* handle; |
| 307 int err = snd_ctl_open(&handle, id.c_str(), 0); | 450 int err = snd_ctl_open(&handle, id.c_str(), 0); |
| 308 if (err != 0) { | 451 if (err != 0) { |
| 309 VLOG(1) << "snd_ctl_open fails: " << snd_strerror(err); | 452 VLOG(1) << "snd_ctl_open fails: " << snd_strerror(err); |
| 310 continue; | 453 continue; |
| 311 } | 454 } |
| 312 err = snd_ctl_card_info(handle, card); | 455 err = snd_ctl_card_info(handle, card); |
| 313 if (err != 0) { | 456 if (err != 0) { |
| 314 VLOG(1) << "snd_ctl_card_info fails: " << snd_strerror(err); | 457 VLOG(1) << "snd_ctl_card_info fails: " << snd_strerror(err); |
| 315 snd_ctl_close(handle); | 458 snd_ctl_close(handle); |
| 316 continue; | 459 continue; |
| 317 } | 460 } |
| 318 // Enumerate any rawmidi devices (not subdevices) and extract MidiDevice. | 461 // Enumerate any rawmidi devices (not subdevices) and extract AlsaRawmidi. |
| 319 for (int device = -1; | 462 for (int device = -1; |
| 320 !snd_ctl_rawmidi_next_device(handle, &device) && device >= 0;) { | 463 !snd_ctl_rawmidi_next_device(handle, &device) && device >= 0;) { |
| 321 bool output; | 464 bool output; |
| 322 bool input; | 465 bool input; |
| 323 snd_rawmidi_info_set_device(midi_out, device); | 466 snd_rawmidi_info_set_device(midi_out, device); |
| 324 snd_rawmidi_info_set_subdevice(midi_out, 0); | 467 snd_rawmidi_info_set_subdevice(midi_out, 0); |
| 325 snd_rawmidi_info_set_stream(midi_out, SND_RAWMIDI_STREAM_OUTPUT); | 468 snd_rawmidi_info_set_stream(midi_out, SND_RAWMIDI_STREAM_OUTPUT); |
| 326 output = snd_ctl_rawmidi_info(handle, midi_out) == 0; | 469 output = snd_ctl_rawmidi_info(handle, midi_out) == 0; |
| 327 snd_rawmidi_info_set_device(midi_in, device); | 470 snd_rawmidi_info_set_device(midi_in, device); |
| 328 snd_rawmidi_info_set_subdevice(midi_in, 0); | 471 snd_rawmidi_info_set_subdevice(midi_in, 0); |
| 329 snd_rawmidi_info_set_stream(midi_in, SND_RAWMIDI_STREAM_INPUT); | 472 snd_rawmidi_info_set_stream(midi_in, SND_RAWMIDI_STREAM_INPUT); |
| 330 input = snd_ctl_rawmidi_info(handle, midi_in) == 0; | 473 input = snd_ctl_rawmidi_info(handle, midi_in) == 0; |
| 331 if (!output && !input) | 474 if (!output && !input) |
| 332 continue; | 475 continue; |
| 333 | 476 |
| 334 // Compute and save ALSA and udev properties. | 477 // Compute and save ALSA and udev properties. |
| 335 snd_rawmidi_info_t* midi = midi_out ? midi_out : midi_in; | 478 snd_rawmidi_info_t* midi = midi_out ? midi_out : midi_in; |
| 336 devices.push_back(new MidiDevice(this, snd_rawmidi_info_get_name(midi), | 479 devices.push_back(new AlsaRawmidi(this, snd_rawmidi_info_get_name(midi), |
| 337 snd_ctl_card_info_get_longname(card), | 480 snd_ctl_card_info_get_longname(card), |
| 338 snd_ctl_card_info_get_driver(card), | 481 snd_ctl_card_info_get_driver(card), |
| 339 card_index)); | 482 card_index)); |
| 340 } | 483 } |
| 341 snd_ctl_close(handle); | 484 snd_ctl_close(handle); |
| 342 } | 485 } |
| 343 | 486 |
| 344 return devices.Pass(); | 487 return devices.Pass(); |
| 345 } | 488 } |
| 346 | 489 |
| 347 void MidiManagerAlsa::EnumeratePorts() { | 490 void MidiManagerAlsa::EnumeratePorts() { |
| 348 ScopedVector<MidiDevice> devices = AllMidiDevices(); | 491 ScopedVector<AlsaRawmidi> devices = AllAlsaRawmidis(); |
| 349 | 492 |
| 350 snd_seq_port_subscribe_t* subs; | 493 snd_seq_port_subscribe_t* subs; |
| 351 snd_seq_port_subscribe_alloca(&subs); | 494 snd_seq_port_subscribe_alloca(&subs); |
| 352 | 495 |
| 353 int in_client_id = snd_seq_client_id(in_client_); | 496 int in_client_id = snd_seq_client_id(in_client_); |
| 354 | 497 |
| 355 // Enumerate all clients. | 498 // Enumerate all clients. |
| 356 snd_seq_client_info_t* client_info; | 499 snd_seq_client_info_t* client_info; |
| 357 snd_seq_client_info_alloca(&client_info); | 500 snd_seq_client_info_alloca(&client_info); |
| 358 snd_seq_port_info_t* port_info; | 501 snd_seq_port_info_t* port_info; |
| (...skipping 10 matching lines...) Expand all Loading... |
| 369 continue; | 512 continue; |
| 370 } | 513 } |
| 371 | 514 |
| 372 // Get client metadata. | 515 // Get client metadata. |
| 373 const std::string client_name = snd_seq_client_info_get_name(client_info); | 516 const std::string client_name = snd_seq_client_info_get_name(client_info); |
| 374 snd_seq_port_info_set_client(port_info, client_id); | 517 snd_seq_port_info_set_client(port_info, client_id); |
| 375 snd_seq_port_info_set_port(port_info, -1); | 518 snd_seq_port_info_set_port(port_info, -1); |
| 376 | 519 |
| 377 std::string manufacturer; | 520 std::string manufacturer; |
| 378 std::string driver; | 521 std::string driver; |
| 379 std::string udev_id_path; | 522 std::string path; |
| 380 std::string udev_id_id; | 523 std::string bus; |
| 524 std::string vendor_id; |
| 525 std::string id; |
| 526 std::string card_name; |
| 527 std::string card_longname; |
| 381 | 528 |
| 382 // Join kernel clients against the list of MidiDevices. | 529 // Join kernel clients against the list of AlsaRawmidis. |
| 383 // In the current ALSA kernel implementation, kernel clients match the | 530 // In the current ALSA kernel implementation, kernel clients match the |
| 384 // kernel devices in the same order, for devices with client_id over | 531 // kernel devices in the same order, for devices with client_id over |
| 385 // kMinimumClientIdForCards. | 532 // kMinimumClientIdForCards. |
| 386 if ((snd_seq_client_info_get_type(client_info) == SND_SEQ_KERNEL_CLIENT) && | 533 if ((snd_seq_client_info_get_type(client_info) == SND_SEQ_KERNEL_CLIENT) && |
| 387 (current_device < devices.size()) && | 534 (current_device < devices.size()) && |
| 388 (client_id >= kMinimumClientIdForCards)) { | 535 (client_id >= kMinimumClientIdForCards)) { |
| 389 const MidiDevice* device = devices[current_device]; | 536 const AlsaRawmidi* device = devices[current_device]; |
| 390 manufacturer = device->manufacturer(); | 537 manufacturer = device->manufacturer(); |
| 391 driver = device->alsa_driver(); | 538 driver = device->alsa_driver(); |
| 392 udev_id_path = device->udev_id_path(); | 539 path = device->path(); |
| 393 udev_id_id = device->udev_id_id(); | 540 bus = device->bus(); |
| 541 vendor_id = device->vendor_id(); |
| 542 id = device->id(); |
| 543 card_name = device->alsa_name(); |
| 544 card_longname = device->alsa_longname(); |
| 394 current_device++; | 545 current_device++; |
| 395 } | 546 } |
| 396 // Enumerate ports. | 547 // Enumerate ports. |
| 397 while (!snd_seq_query_next_port(in_client_, port_info)) { | 548 while (!snd_seq_query_next_port(in_client_, port_info)) { |
| 398 unsigned int port_type = snd_seq_port_info_get_type(port_info); | 549 unsigned int port_type = snd_seq_port_info_get_type(port_info); |
| 399 if (port_type & SND_SEQ_PORT_TYPE_MIDI_GENERIC) { | 550 if (port_type & SND_SEQ_PORT_TYPE_MIDI_GENERIC) { |
| 400 const snd_seq_addr_t* addr = snd_seq_port_info_get_addr(port_info); | 551 const snd_seq_addr_t* addr = snd_seq_port_info_get_addr(port_info); |
| 401 const std::string name = snd_seq_port_info_get_name(port_info); | 552 const std::string name = snd_seq_port_info_get_name(port_info); |
| 402 const std::string id_suffix = | |
| 403 base::StringPrintf("%d:%d/%s/%s", addr->client, addr->port, | |
| 404 udev_id_path.c_str(), udev_id_id.c_str()); | |
| 405 std::string version; | 553 std::string version; |
| 406 if (!driver.empty()) { | 554 if (!driver.empty()) { |
| 407 version = driver + " / "; | 555 version = driver + " / "; |
| 408 } | 556 } |
| 409 version += base::StringPrintf("ALSA library version %d.%d.%d", | 557 version += base::StringPrintf("ALSA library version %d.%d.%d", |
| 410 SND_LIB_MAJOR, | 558 SND_LIB_MAJOR, |
| 411 SND_LIB_MINOR, | 559 SND_LIB_MINOR, |
| 412 SND_LIB_SUBMINOR); | 560 SND_LIB_SUBMINOR); |
| 413 unsigned int caps = snd_seq_port_info_get_capability(port_info); | 561 unsigned int caps = snd_seq_port_info_get_capability(port_info); |
| 414 if ((caps & kRequiredInputPortCaps) == kRequiredInputPortCaps) { | 562 if ((caps & kRequiredInputPortCaps) == kRequiredInputPortCaps) { |
| 415 // Subscribe to this port. | 563 // Subscribe to this port. |
| 416 const snd_seq_addr_t* sender = snd_seq_port_info_get_addr(port_info); | 564 const snd_seq_addr_t* sender = snd_seq_port_info_get_addr(port_info); |
| 417 snd_seq_addr_t dest; | 565 snd_seq_addr_t dest; |
| 418 dest.client = snd_seq_client_id(in_client_); | 566 dest.client = snd_seq_client_id(in_client_); |
| 419 dest.port = in_port_; | 567 dest.port = in_port_; |
| 420 snd_seq_port_subscribe_set_sender(subs, sender); | 568 snd_seq_port_subscribe_set_sender(subs, sender); |
| 421 snd_seq_port_subscribe_set_dest(subs, &dest); | 569 snd_seq_port_subscribe_set_dest(subs, &dest); |
| 422 int err = snd_seq_subscribe_port(in_client_, subs); | 570 int err = snd_seq_subscribe_port(in_client_, subs); |
| 423 if (err != 0) { | 571 if (err != 0) { |
| 424 VLOG(1) << "snd_seq_subscribe_port fails: " << snd_strerror(err); | 572 VLOG(1) << "snd_seq_subscribe_port fails: " << snd_strerror(err); |
| 425 } else { | 573 } else { |
| 426 source_map_[AddrToInt(sender)] = current_input++; | 574 source_map_[AddrToInt(sender)] = current_input++; |
| 427 AddInputPort( | 575 const AlsaPortMetadata metadata(path, bus, id, addr, client_name, |
| 428 MidiPortInfo(base::StringPrintf("input/%s", id_suffix.c_str()), | 576 name, card_name, card_longname, |
| 429 manufacturer, name, version, MIDI_PORT_OPENED)); | 577 AlsaPortMetadata::Type::kInput); |
| 578 const std::string id = metadata.OpaqueKey(); |
| 579 AddInputPort(MidiPortInfo(id.c_str(), manufacturer, name, version, |
| 580 MIDI_PORT_OPENED)); |
| 430 } | 581 } |
| 431 } | 582 } |
| 432 if ((caps & kRequiredOutputPortCaps) == kRequiredOutputPortCaps) { | 583 if ((caps & kRequiredOutputPortCaps) == kRequiredOutputPortCaps) { |
| 433 // Create a port for us to send on. | 584 // Create a port for us to send on. |
| 434 int out_port = | 585 int out_port = |
| 435 snd_seq_create_simple_port(out_client_, NULL, | 586 snd_seq_create_simple_port(out_client_, NULL, |
| 436 SND_SEQ_PORT_CAP_READ | | 587 SND_SEQ_PORT_CAP_READ | |
| 437 SND_SEQ_PORT_CAP_NO_EXPORT, | 588 SND_SEQ_PORT_CAP_NO_EXPORT, |
| 438 SND_SEQ_PORT_TYPE_MIDI_GENERIC | | 589 SND_SEQ_PORT_TYPE_MIDI_GENERIC | |
| 439 SND_SEQ_PORT_TYPE_APPLICATION); | 590 SND_SEQ_PORT_TYPE_APPLICATION); |
| 440 if (out_port < 0) { | 591 if (out_port < 0) { |
| 441 VLOG(1) << "snd_seq_create_simple_port fails: " | 592 VLOG(1) << "snd_seq_create_simple_port fails: " |
| 442 << snd_strerror(out_port); | 593 << snd_strerror(out_port); |
| 443 // Skip this output port for now. | 594 // Skip this output port for now. |
| 444 continue; | 595 continue; |
| 445 } | 596 } |
| 446 | 597 |
| 447 // Activate port subscription. | 598 // Activate port subscription. |
| 448 snd_seq_addr_t sender; | 599 snd_seq_addr_t sender; |
| 449 const snd_seq_addr_t* dest = snd_seq_port_info_get_addr(port_info); | 600 const snd_seq_addr_t* dest = snd_seq_port_info_get_addr(port_info); |
| 450 sender.client = snd_seq_client_id(out_client_); | 601 sender.client = snd_seq_client_id(out_client_); |
| 451 sender.port = out_port; | 602 sender.port = out_port; |
| 452 snd_seq_port_subscribe_set_sender(subs, &sender); | 603 snd_seq_port_subscribe_set_sender(subs, &sender); |
| 453 snd_seq_port_subscribe_set_dest(subs, dest); | 604 snd_seq_port_subscribe_set_dest(subs, dest); |
| 454 int err = snd_seq_subscribe_port(out_client_, subs); | 605 int err = snd_seq_subscribe_port(out_client_, subs); |
| 455 if (err != 0) { | 606 if (err != 0) { |
| 456 VLOG(1) << "snd_seq_subscribe_port fails: " << snd_strerror(err); | 607 VLOG(1) << "snd_seq_subscribe_port fails: " << snd_strerror(err); |
| 457 snd_seq_delete_simple_port(out_client_, out_port); | 608 snd_seq_delete_simple_port(out_client_, out_port); |
| 458 } else { | 609 } else { |
| 459 snd_midi_event_t* encoder; | |
| 460 snd_midi_event_new(kSendBufferSize, &encoder); | |
| 461 encoders_.push_back(encoder); | |
| 462 out_ports_.push_back(out_port); | 610 out_ports_.push_back(out_port); |
| 463 AddOutputPort( | 611 const AlsaPortMetadata metadata(path, bus, id, addr, client_name, |
| 464 MidiPortInfo(base::StringPrintf("output/%s", id_suffix.c_str()), | 612 name, card_name, card_longname, |
| 465 manufacturer, name, version, MIDI_PORT_OPENED)); | 613 AlsaPortMetadata::Type::kOutput); |
| 614 const std::string id = metadata.OpaqueKey(); |
| 615 AddOutputPort(MidiPortInfo(id.c_str(), manufacturer, name, version, |
| 616 MIDI_PORT_OPENED)); |
| 466 } | 617 } |
| 467 } | 618 } |
| 468 } | 619 } |
| 469 } | 620 } |
| 470 } | 621 } |
| 471 } | 622 } |
| 472 | 623 |
| 473 void MidiManagerAlsa::SendMidiData(uint32 port_index, | 624 void MidiManagerAlsa::SendMidiData(uint32 port_index, |
| 474 const std::vector<uint8>& data) { | 625 const std::vector<uint8>& data) { |
| 475 DCHECK(send_thread_.message_loop_proxy()->BelongsToCurrentThread()); | 626 DCHECK(send_thread_.message_loop_proxy()->BelongsToCurrentThread()); |
| 476 | 627 |
| 477 snd_midi_event_t* encoder = encoders_[port_index]; | 628 snd_midi_event_t* encoder; |
| 629 snd_midi_event_new(kSendBufferSize, &encoder); |
| 478 for (unsigned int i = 0; i < data.size(); i++) { | 630 for (unsigned int i = 0; i < data.size(); i++) { |
| 479 snd_seq_event_t event; | 631 snd_seq_event_t event; |
| 480 int result = snd_midi_event_encode_byte(encoder, data[i], &event); | 632 int result = snd_midi_event_encode_byte(encoder, data[i], &event); |
| 481 if (result == 1) { | 633 if (result == 1) { |
| 482 // Full event, send it. | 634 // Full event, send it. |
| 483 snd_seq_ev_set_source(&event, out_ports_[port_index]); | 635 snd_seq_ev_set_source(&event, out_ports_[port_index]); |
| 484 snd_seq_ev_set_subs(&event); | 636 snd_seq_ev_set_subs(&event); |
| 485 snd_seq_ev_set_direct(&event); | 637 snd_seq_ev_set_direct(&event); |
| 486 snd_seq_event_output_direct(out_client_, &event); | 638 snd_seq_event_output_direct(out_client_, &event); |
| 487 } | 639 } |
| 488 } | 640 } |
| 641 snd_midi_event_free(encoder); |
| 489 } | 642 } |
| 490 | 643 |
| 491 void MidiManagerAlsa::ScheduleEventLoop() { | 644 void MidiManagerAlsa::ScheduleEventLoop() { |
| 492 event_thread_.message_loop()->PostTask( | 645 event_thread_.message_loop()->PostTask( |
| 493 FROM_HERE, | 646 FROM_HERE, |
| 494 base::Bind(&MidiManagerAlsa::EventLoop, base::Unretained(this))); | 647 base::Bind(&MidiManagerAlsa::EventLoop, base::Unretained(this))); |
| 495 } | 648 } |
| 496 | 649 |
| 497 void MidiManagerAlsa::EventLoop() { | 650 void MidiManagerAlsa::EventLoop() { |
| 498 // Read available incoming MIDI data. | 651 // Read available incoming MIDI data. |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 572 } | 725 } |
| 573 } | 726 } |
| 574 } | 727 } |
| 575 } | 728 } |
| 576 | 729 |
| 577 MidiManager* MidiManager::Create() { | 730 MidiManager* MidiManager::Create() { |
| 578 return new MidiManagerAlsa(); | 731 return new MidiManagerAlsa(); |
| 579 } | 732 } |
| 580 | 733 |
| 581 } // namespace media | 734 } // namespace media |
| OLD | NEW |