| Index: media/midi/midi_manager_alsa.cc
|
| diff --git a/media/midi/midi_manager_alsa.cc b/media/midi/midi_manager_alsa.cc
|
| index 6c91e13b476edd3dede2185abb1d16555134ec2a..74e2f421b11968e0fb64c487f9a176a2f6f99cfa 100644
|
| --- a/media/midi/midi_manager_alsa.cc
|
| +++ b/media/midi/midi_manager_alsa.cc
|
| @@ -30,6 +30,14 @@ namespace {
|
| // realtime messages with respect to sysex.
|
| const size_t kSendBufferSize = 256;
|
|
|
| +// Minimum client id for which we will have ALSA card devices for. When we
|
| +// are searching for card devices (used to get the path, id, and manufacturer),
|
| +// we don't want to get confused by kernel clients that do not have a card.
|
| +// See seq_clientmgr.c in the ALSA code for this.
|
| +// TODO(agoode): Add proper client -> card export from the kernel to avoid
|
| +// hardcoding.
|
| +const int kMinimumClientIdForCards = 16;
|
| +
|
| // Constants for the capabilities we search for in inputs and outputs.
|
| // See http://www.alsa-project.org/alsa-doc/alsa-lib/seq.html.
|
| const unsigned int kRequiredInputPortCaps =
|
| @@ -60,6 +68,38 @@ MidiManagerAlsa::MidiManagerAlsa()
|
| snd_midi_event_no_status(decoder_, 1);
|
| }
|
|
|
| +MidiManagerAlsa::~MidiManagerAlsa() {
|
| + // Tell the event thread it will soon be time to shut down. This gives
|
| + // us assurance the thread will stop in case the SND_SEQ_EVENT_CLIENT_EXIT
|
| + // message is lost.
|
| + {
|
| + base::AutoLock lock(shutdown_lock_);
|
| + event_thread_shutdown_ = true;
|
| + }
|
| +
|
| + // Stop the send thread.
|
| + send_thread_.Stop();
|
| +
|
| + // Close the out client. This will trigger the event thread to stop,
|
| + // because of SND_SEQ_EVENT_CLIENT_EXIT.
|
| + if (out_client_)
|
| + snd_seq_close(out_client_);
|
| +
|
| + // Wait for the event thread to stop.
|
| + event_thread_.Stop();
|
| +
|
| + // Close the in client.
|
| + if (in_client_)
|
| + snd_seq_close(in_client_);
|
| +
|
| + // Free the decoder.
|
| + snd_midi_event_free(decoder_);
|
| +
|
| + // Free the encoders.
|
| + for (EncoderList::iterator i = encoders_.begin(); i != encoders_.end(); ++i)
|
| + snd_midi_event_free(*i);
|
| +}
|
| +
|
| void MidiManagerAlsa::StartInitialization() {
|
| // TODO(agoode): Move off I/O thread. See http://crbug.com/374341.
|
|
|
| @@ -118,17 +158,150 @@ void MidiManagerAlsa::StartInitialization() {
|
| return CompleteInitialization(MIDI_INITIALIZATION_ERROR);
|
| }
|
|
|
| - // Extract the list of manufacturers for the hardware MIDI
|
| - // devices. This won't work for all devices. It is also brittle until
|
| - // hotplug is implemented. (See http://crbug.com/431489.)
|
| - ScopedVector<CardInfo> cards;
|
| + EnumeratePorts();
|
| +
|
| + event_thread_.Start();
|
| + event_thread_.message_loop()->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(&MidiManagerAlsa::ScheduleEventLoop, base::Unretained(this)));
|
| +
|
| + CompleteInitialization(MIDI_OK);
|
| +}
|
| +
|
| +void MidiManagerAlsa::DispatchSendMidiData(MidiManagerClient* client,
|
| + uint32 port_index,
|
| + const std::vector<uint8>& data,
|
| + double timestamp) {
|
| + if (out_ports_.size() <= port_index)
|
| + return;
|
| +
|
| + // Not correct right now. http://crbug.com/374341.
|
| + if (!send_thread_.IsRunning())
|
| + send_thread_.Start();
|
| +
|
| + base::TimeDelta delay;
|
| + if (timestamp != 0.0) {
|
| + base::TimeTicks time_to_send =
|
| + base::TimeTicks() + base::TimeDelta::FromMicroseconds(
|
| + timestamp * base::Time::kMicrosecondsPerSecond);
|
| + delay = std::max(time_to_send - base::TimeTicks::Now(), base::TimeDelta());
|
| + }
|
| +
|
| + send_thread_.message_loop()->PostDelayedTask(
|
| + FROM_HERE, base::Bind(&MidiManagerAlsa::SendMidiData,
|
| + base::Unretained(this), port_index, data),
|
| + delay);
|
| +
|
| + // Acknowledge send.
|
| + send_thread_.message_loop()->PostTask(
|
| + FROM_HERE, base::Bind(&MidiManagerClient::AccumulateMidiBytesSent,
|
| + base::Unretained(client), data.size()));
|
| +}
|
| +
|
| +MidiManagerAlsa::MidiDevice::MidiDevice(const MidiManagerAlsa* outer,
|
| + const std::string& alsa_name,
|
| + const std::string& alsa_longname,
|
| + const std::string& alsa_driver,
|
| + int card_index)
|
| + : alsa_name_(alsa_name), alsa_driver_(alsa_driver) {
|
| + // Get udev properties if available.
|
| + std::string udev_id_vendor;
|
| + std::string udev_id_vendor_id;
|
| + std::string udev_id_vendor_from_database;
|
| +
|
| +#if defined(USE_UDEV)
|
| + const std::string sysname = base::StringPrintf("card%i", card_index);
|
| + device::ScopedUdevDevicePtr udev_device(
|
| + device::udev_device_new_from_subsystem_sysname(outer->udev_.get(),
|
| + "sound", sysname.c_str()));
|
| + udev_id_vendor = device::UdevDecodeString(
|
| + device::UdevDeviceGetPropertyValue(udev_device.get(), "ID_VENDOR_ENC"));
|
| + udev_id_vendor_id =
|
| + device::UdevDeviceGetPropertyValue(udev_device.get(), "ID_VENDOR_ID");
|
| + udev_id_vendor_from_database = device::UdevDeviceGetPropertyValue(
|
| + udev_device.get(), "ID_VENDOR_FROM_DATABASE");
|
| +
|
| + udev_id_path_ =
|
| + device::UdevDeviceGetPropertyValue(udev_device.get(), "ID_PATH");
|
| + udev_id_id_ = device::UdevDeviceGetPropertyValue(udev_device.get(), "ID_ID");
|
| +#endif // defined(USE_UDEV)
|
| +
|
| + manufacturer_ = ExtractManufacturerString(udev_id_vendor, udev_id_vendor_id,
|
| + udev_id_vendor_from_database,
|
| + alsa_name, alsa_longname);
|
| +}
|
| +
|
| +MidiManagerAlsa::MidiDevice::~MidiDevice() {
|
| +}
|
| +
|
| +const std::string MidiManagerAlsa::MidiDevice::alsa_name() const {
|
| + return alsa_name_;
|
| +}
|
| +
|
| +const std::string MidiManagerAlsa::MidiDevice::manufacturer() const {
|
| + return manufacturer_;
|
| +}
|
| +
|
| +const std::string MidiManagerAlsa::MidiDevice::alsa_driver() const {
|
| + return alsa_driver_;
|
| +}
|
| +
|
| +const std::string MidiManagerAlsa::MidiDevice::udev_id_path() const {
|
| + return udev_id_path_;
|
| +}
|
| +
|
| +const std::string MidiManagerAlsa::MidiDevice::udev_id_id() const {
|
| + return udev_id_id_;
|
| +}
|
| +
|
| +// static
|
| +std::string MidiManagerAlsa::MidiDevice::ExtractManufacturerString(
|
| + 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) {
|
| + // Let's try to determine the manufacturer. Here is the ordered preference
|
| + // in extraction:
|
| + // 1. Vendor name from the USB device iManufacturer string, from
|
| + // the udev property ID_VENDOR_ENC.
|
| + // 2. Vendor name from the udev database (property ID_VENDOR_FROM_DATABASE).
|
| + // 3. Heuristic from ALSA.
|
| +
|
| + // Is the vendor string not just the USB vendor hex id?
|
| + if (udev_id_vendor != udev_id_vendor_id) {
|
| + return udev_id_vendor;
|
| + }
|
| +
|
| + // Is there a vendor string in the hardware database?
|
| + if (!udev_id_vendor_from_database.empty()) {
|
| + return udev_id_vendor_from_database;
|
| + }
|
| +
|
| + // Ok, udev gave us nothing useful, or was unavailable. So try a heuristic.
|
| + // We assume that card longname is in the format of
|
| + // "<manufacturer> <name> at <bus>". Otherwise, we give up to detect
|
| + // a manufacturer name here.
|
| + size_t at_index = alsa_longname.rfind(" at ");
|
| + if (std::string::npos != at_index) {
|
| + size_t name_index = alsa_longname.rfind(alsa_name, at_index - 1);
|
| + if (std::string::npos != name_index)
|
| + return alsa_longname.substr(0, name_index - 1);
|
| + }
|
| +
|
| + // Failure.
|
| + return "";
|
| +}
|
| +
|
| +ScopedVector<MidiManagerAlsa::MidiDevice> MidiManagerAlsa::AllMidiDevices() {
|
| + ScopedVector<MidiDevice> devices;
|
| snd_ctl_card_info_t* card;
|
| snd_rawmidi_info_t* midi_out;
|
| snd_rawmidi_info_t* midi_in;
|
| snd_ctl_card_info_alloca(&card);
|
| snd_rawmidi_info_alloca(&midi_out);
|
| snd_rawmidi_info_alloca(&midi_in);
|
| - for (int card_index = -1; !snd_card_next(&card_index) && card_index >= 0; ) {
|
| + for (int card_index = -1; !snd_card_next(&card_index) && card_index >= 0;) {
|
| const std::string id = base::StringPrintf("hw:CARD=%i", card_index);
|
| snd_ctl_t* handle;
|
| int err = snd_ctl_open(&handle, id.c_str(), 0);
|
| @@ -142,9 +315,9 @@ void MidiManagerAlsa::StartInitialization() {
|
| snd_ctl_close(handle);
|
| continue;
|
| }
|
| - // Enumerate any rawmidi devices (not subdevices) and extract CardInfo.
|
| + // Enumerate any rawmidi devices (not subdevices) and extract MidiDevice.
|
| for (int device = -1;
|
| - !snd_ctl_rawmidi_next_device(handle, &device) && device >= 0; ) {
|
| + !snd_ctl_rawmidi_next_device(handle, &device) && device >= 0;) {
|
| bool output;
|
| bool input;
|
| snd_rawmidi_info_set_device(midi_out, device);
|
| @@ -158,50 +331,67 @@ void MidiManagerAlsa::StartInitialization() {
|
| if (!output && !input)
|
| continue;
|
|
|
| - // Compute and save Alsa and udev properties.
|
| + // Compute and save ALSA and udev properties.
|
| snd_rawmidi_info_t* midi = midi_out ? midi_out : midi_in;
|
| - cards.push_back(new CardInfo(
|
| - this,
|
| - snd_rawmidi_info_get_name(midi),
|
| - snd_ctl_card_info_get_longname(card),
|
| - snd_ctl_card_info_get_driver(card),
|
| - card_index));
|
| + devices.push_back(new MidiDevice(this, snd_rawmidi_info_get_name(midi),
|
| + snd_ctl_card_info_get_longname(card),
|
| + snd_ctl_card_info_get_driver(card),
|
| + card_index));
|
| }
|
| snd_ctl_close(handle);
|
| }
|
|
|
| - // Enumerate all ports in all clients.
|
| + return devices.Pass();
|
| +}
|
| +
|
| +void MidiManagerAlsa::EnumeratePorts() {
|
| + ScopedVector<MidiDevice> devices = AllMidiDevices();
|
| +
|
| + snd_seq_port_subscribe_t* subs;
|
| + snd_seq_port_subscribe_alloca(&subs);
|
| +
|
| + int in_client_id = snd_seq_client_id(in_client_);
|
| +
|
| + // Enumerate all clients.
|
| snd_seq_client_info_t* client_info;
|
| snd_seq_client_info_alloca(&client_info);
|
| snd_seq_port_info_t* port_info;
|
| snd_seq_port_info_alloca(&port_info);
|
|
|
| - snd_seq_client_info_set_client(client_info, -1);
|
| // Enumerate clients.
|
| + snd_seq_client_info_set_client(client_info, -1);
|
| uint32 current_input = 0;
|
| - unsigned int current_card = 0;
|
| + unsigned int current_device = 0;
|
| while (!snd_seq_query_next_client(in_client_, client_info)) {
|
| int client_id = snd_seq_client_info_get_client(client_info);
|
| if ((client_id == in_client_id) || (client_id == out_client_id_)) {
|
| // Skip our own clients.
|
| continue;
|
| }
|
| +
|
| + // Get client metadata.
|
| const std::string client_name = snd_seq_client_info_get_name(client_info);
|
| snd_seq_port_info_set_client(port_info, client_id);
|
| snd_seq_port_info_set_port(port_info, -1);
|
|
|
| std::string manufacturer;
|
| std::string driver;
|
| - // In the current Alsa kernel implementation, hardware clients match the
|
| - // cards in the same order.
|
| + std::string udev_id_path;
|
| + std::string udev_id_id;
|
| +
|
| + // Join kernel clients against the list of MidiDevices.
|
| + // In the current ALSA kernel implementation, kernel clients match the
|
| + // kernel devices in the same order, for devices with client_id over
|
| + // kMinimumClientIdForCards.
|
| if ((snd_seq_client_info_get_type(client_info) == SND_SEQ_KERNEL_CLIENT) &&
|
| - (current_card < cards.size())) {
|
| - const CardInfo* info = cards[current_card];
|
| - if (info->alsa_name() == client_name) {
|
| - manufacturer = info->manufacturer();
|
| - driver = info->alsa_driver();
|
| - current_card++;
|
| - }
|
| + (current_device < devices.size()) &&
|
| + (client_id >= kMinimumClientIdForCards)) {
|
| + const MidiDevice* device = devices[current_device];
|
| + manufacturer = device->manufacturer();
|
| + driver = device->alsa_driver();
|
| + udev_id_path = device->udev_id_path();
|
| + udev_id_id = device->udev_id_id();
|
| + current_device++;
|
| }
|
| // Enumerate ports.
|
| while (!snd_seq_query_next_port(in_client_, port_info)) {
|
| @@ -209,10 +399,9 @@ void MidiManagerAlsa::StartInitialization() {
|
| if (port_type & SND_SEQ_PORT_TYPE_MIDI_GENERIC) {
|
| const snd_seq_addr_t* addr = snd_seq_port_info_get_addr(port_info);
|
| const std::string name = snd_seq_port_info_get_name(port_info);
|
| - const std::string id = base::StringPrintf("%d:%d %s",
|
| - addr->client,
|
| - addr->port,
|
| - name.c_str());
|
| + const std::string id_suffix =
|
| + base::StringPrintf("%d:%d/%s/%s", addr->client, addr->port,
|
| + udev_id_path.c_str(), udev_id_id.c_str());
|
| std::string version;
|
| if (!driver.empty()) {
|
| version = driver + " / ";
|
| @@ -230,13 +419,14 @@ void MidiManagerAlsa::StartInitialization() {
|
| dest.port = in_port_;
|
| snd_seq_port_subscribe_set_sender(subs, sender);
|
| snd_seq_port_subscribe_set_dest(subs, &dest);
|
| - err = snd_seq_subscribe_port(in_client_, subs);
|
| + int err = snd_seq_subscribe_port(in_client_, subs);
|
| if (err != 0) {
|
| VLOG(1) << "snd_seq_subscribe_port fails: " << snd_strerror(err);
|
| } else {
|
| source_map_[AddrToInt(sender)] = current_input++;
|
| - AddInputPort(MidiPortInfo(
|
| - id, manufacturer, name, version, MIDI_PORT_OPENED));
|
| + AddInputPort(
|
| + MidiPortInfo(base::StringPrintf("input/%s", id_suffix.c_str()),
|
| + manufacturer, name, version, MIDI_PORT_OPENED));
|
| }
|
| }
|
| if ((caps & kRequiredOutputPortCaps) == kRequiredOutputPortCaps) {
|
| @@ -261,7 +451,7 @@ void MidiManagerAlsa::StartInitialization() {
|
| sender.port = out_port;
|
| snd_seq_port_subscribe_set_sender(subs, &sender);
|
| snd_seq_port_subscribe_set_dest(subs, dest);
|
| - err = snd_seq_subscribe_port(out_client_, subs);
|
| + int err = snd_seq_subscribe_port(out_client_, subs);
|
| if (err != 0) {
|
| VLOG(1) << "snd_seq_subscribe_port fails: " << snd_strerror(err);
|
| snd_seq_delete_simple_port(out_client_, out_port);
|
| @@ -270,108 +460,14 @@ void MidiManagerAlsa::StartInitialization() {
|
| snd_midi_event_new(kSendBufferSize, &encoder);
|
| encoders_.push_back(encoder);
|
| out_ports_.push_back(out_port);
|
| - AddOutputPort(MidiPortInfo(
|
| - id, manufacturer, name, version, MIDI_PORT_OPENED));
|
| + AddOutputPort(
|
| + MidiPortInfo(base::StringPrintf("output/%s", id_suffix.c_str()),
|
| + manufacturer, name, version, MIDI_PORT_OPENED));
|
| }
|
| }
|
| }
|
| }
|
| }
|
| -
|
| - event_thread_.Start();
|
| - event_thread_.message_loop()->PostTask(
|
| - FROM_HERE,
|
| - base::Bind(&MidiManagerAlsa::EventReset, base::Unretained(this)));
|
| -
|
| - CompleteInitialization(MIDI_OK);
|
| -}
|
| -
|
| -MidiManagerAlsa::~MidiManagerAlsa() {
|
| - // Tell the event thread it will soon be time to shut down. This gives
|
| - // us assurance the thread will stop in case the SND_SEQ_EVENT_CLIENT_EXIT
|
| - // message is lost.
|
| - {
|
| - base::AutoLock lock(shutdown_lock_);
|
| - event_thread_shutdown_ = true;
|
| - }
|
| -
|
| - // Stop the send thread.
|
| - send_thread_.Stop();
|
| -
|
| - // Close the out client. This will trigger the event thread to stop,
|
| - // because of SND_SEQ_EVENT_CLIENT_EXIT.
|
| - if (out_client_)
|
| - snd_seq_close(out_client_);
|
| -
|
| - // Wait for the event thread to stop.
|
| - event_thread_.Stop();
|
| -
|
| - // Close the in client.
|
| - if (in_client_)
|
| - snd_seq_close(in_client_);
|
| -
|
| - // Free the decoder.
|
| - snd_midi_event_free(decoder_);
|
| -
|
| - // Free the encoders.
|
| - for (EncoderList::iterator i = encoders_.begin(); i != encoders_.end(); ++i)
|
| - snd_midi_event_free(*i);
|
| -}
|
| -
|
| -MidiManagerAlsa::CardInfo::CardInfo(
|
| - const MidiManagerAlsa* outer,
|
| - const std::string& alsa_name, const std::string& alsa_longname,
|
| - const std::string& alsa_driver, int card_index)
|
| - : alsa_name_(alsa_name), alsa_driver_(alsa_driver) {
|
| - // Get udev properties if available.
|
| - std::string udev_id_vendor;
|
| - std::string udev_id_vendor_id;
|
| - std::string udev_id_vendor_from_database;
|
| -
|
| -#if defined(USE_UDEV)
|
| - const std::string sysname = base::StringPrintf("card%i", card_index);
|
| - device::ScopedUdevDevicePtr udev_device(
|
| - device::udev_device_new_from_subsystem_sysname(
|
| - outer->udev_.get(), "sound", sysname.c_str()));
|
| - udev_id_vendor = device::UdevDecodeString(device::UdevDeviceGetPropertyValue(
|
| - udev_device.get(), "ID_VENDOR_ENC"));
|
| - udev_id_vendor_id = device::UdevDeviceGetPropertyValue(
|
| - udev_device.get(), "ID_VENDOR_ID");
|
| - udev_id_vendor_from_database = device::UdevDeviceGetPropertyValue(
|
| - udev_device.get(), "ID_VENDOR_FROM_DATABASE");
|
| -
|
| - udev_id_path_ = device::UdevDeviceGetPropertyValue(
|
| - udev_device.get(), "ID_PATH");
|
| - udev_id_id_ = device::UdevDeviceGetPropertyValue(
|
| - udev_device.get(), "ID_ID");
|
| -#endif // defined(USE_UDEV)
|
| -
|
| - manufacturer_ = ExtractManufacturerString(
|
| - udev_id_vendor, udev_id_vendor_id, udev_id_vendor_from_database,
|
| - alsa_name, alsa_longname);
|
| -}
|
| -
|
| -MidiManagerAlsa::CardInfo::~CardInfo() {
|
| -}
|
| -
|
| -const std::string MidiManagerAlsa::CardInfo::alsa_name() const {
|
| - return alsa_name_;
|
| -}
|
| -
|
| -const std::string MidiManagerAlsa::CardInfo::manufacturer() const {
|
| - return manufacturer_;
|
| -}
|
| -
|
| -const std::string MidiManagerAlsa::CardInfo::alsa_driver() const {
|
| - return alsa_driver_;
|
| -}
|
| -
|
| -const std::string MidiManagerAlsa::CardInfo::udev_id_path() const {
|
| - return udev_id_path_;
|
| -}
|
| -
|
| -const std::string MidiManagerAlsa::CardInfo::udev_id_id() const {
|
| - return udev_id_id_;
|
| }
|
|
|
| void MidiManagerAlsa::SendMidiData(uint32 port_index,
|
| @@ -392,38 +488,7 @@ void MidiManagerAlsa::SendMidiData(uint32 port_index,
|
| }
|
| }
|
|
|
| -void MidiManagerAlsa::DispatchSendMidiData(MidiManagerClient* client,
|
| - uint32 port_index,
|
| - const std::vector<uint8>& data,
|
| - double timestamp) {
|
| - if (out_ports_.size() <= port_index)
|
| - return;
|
| -
|
| - // Not correct right now. http://crbug.com/374341.
|
| - if (!send_thread_.IsRunning())
|
| - send_thread_.Start();
|
| -
|
| - base::TimeDelta delay;
|
| - if (timestamp != 0.0) {
|
| - base::TimeTicks time_to_send =
|
| - base::TimeTicks() + base::TimeDelta::FromMicroseconds(
|
| - timestamp * base::Time::kMicrosecondsPerSecond);
|
| - delay = std::max(time_to_send - base::TimeTicks::Now(), base::TimeDelta());
|
| - }
|
| -
|
| - send_thread_.message_loop()->PostDelayedTask(
|
| - FROM_HERE,
|
| - base::Bind(&MidiManagerAlsa::SendMidiData, base::Unretained(this),
|
| - port_index, data), delay);
|
| -
|
| - // Acknowledge send.
|
| - send_thread_.message_loop()->PostTask(
|
| - FROM_HERE,
|
| - base::Bind(&MidiManagerClient::AccumulateMidiBytesSent,
|
| - base::Unretained(client), data.size()));
|
| -}
|
| -
|
| -void MidiManagerAlsa::EventReset() {
|
| +void MidiManagerAlsa::ScheduleEventLoop() {
|
| event_thread_.message_loop()->PostTask(
|
| FROM_HERE,
|
| base::Bind(&MidiManagerAlsa::EventLoop, base::Unretained(this)));
|
| @@ -434,95 +499,79 @@ void MidiManagerAlsa::EventLoop() {
|
| snd_seq_event_t* event;
|
| int err = snd_seq_event_input(in_client_, &event);
|
| double timestamp = (base::TimeTicks::Now() - base::TimeTicks()).InSecondsF();
|
| +
|
| + // Handle errors.
|
| if (err == -ENOSPC) {
|
| VLOG(1) << "snd_seq_event_input detected buffer overrun";
|
| -
|
| - // We've lost events: check another way to see if we need to shut down.
|
| - base::AutoLock lock(shutdown_lock_);
|
| - if (event_thread_shutdown_) {
|
| - return;
|
| - }
|
| + // We've lost events: check another way to see if we need to shut down.
|
| + base::AutoLock lock(shutdown_lock_);
|
| + if (!event_thread_shutdown_)
|
| + ScheduleEventLoop();
|
| + return;
|
| } else if (err < 0) {
|
| - VLOG(1) << "snd_seq_event_input fails: " << snd_strerror(err);
|
| - return;
|
| - } else {
|
| - // Check for disconnection of out client. This means "shut down".
|
| - if (event->source.client == SND_SEQ_CLIENT_SYSTEM &&
|
| - event->source.port == SND_SEQ_PORT_SYSTEM_ANNOUNCE &&
|
| - event->type == SND_SEQ_EVENT_CLIENT_EXIT &&
|
| - event->data.addr.client == out_client_id_) {
|
| - return;
|
| - }
|
| + VLOG(1) << "snd_seq_event_input fails: " << snd_strerror(err);
|
| + // TODO(agoode): Use RecordAction() or similar to log this.
|
| + return;
|
| + }
|
|
|
| - std::map<int, uint32>::iterator source_it =
|
| - source_map_.find(AddrToInt(&event->source));
|
| - if (source_it != source_map_.end()) {
|
| - uint32 source = source_it->second;
|
| - if (event->type == SND_SEQ_EVENT_SYSEX) {
|
| - // Special! Variable-length sysex.
|
| - ReceiveMidiData(source, static_cast<const uint8*>(event->data.ext.ptr),
|
| - event->data.ext.len,
|
| - timestamp);
|
| - } else {
|
| - // Otherwise, decode this and send that on.
|
| - unsigned char buf[12];
|
| - long count = snd_midi_event_decode(decoder_, buf, sizeof(buf), event);
|
| - if (count <= 0) {
|
| - if (count != -ENOENT) {
|
| - // ENOENT means that it's not a MIDI message, which is not an
|
| - // error, but other negative values are errors for us.
|
| - VLOG(1) << "snd_midi_event_decoder fails " << snd_strerror(count);
|
| - }
|
| - } else {
|
| - ReceiveMidiData(source, buf, count, timestamp);
|
| - }
|
| - }
|
| + // Handle announce events.
|
| + if (event->source.client == SND_SEQ_CLIENT_SYSTEM &&
|
| + event->source.port == SND_SEQ_PORT_SYSTEM_ANNOUNCE) {
|
| + switch (event->type) {
|
| + case SND_SEQ_EVENT_CLIENT_START:
|
| + // TODO(agoode): rescan hardware devices.
|
| + break;
|
| +
|
| + case SND_SEQ_EVENT_CLIENT_EXIT:
|
| + // Check for disconnection of our "out" client. This means "shut down".
|
| + if (event->data.addr.client == out_client_id_)
|
| + return;
|
| +
|
| + // TODO(agoode): remove all ports for a client.
|
| + break;
|
| +
|
| + case SND_SEQ_EVENT_PORT_START:
|
| + // TODO(agoode): add port.
|
| + break;
|
| +
|
| + case SND_SEQ_EVENT_PORT_EXIT:
|
| + // TODO(agoode): remove port.
|
| + break;
|
| }
|
| }
|
|
|
| + ProcessSingleEvent(event, timestamp);
|
| +
|
| // Do again.
|
| - event_thread_.message_loop()->PostTask(
|
| - FROM_HERE,
|
| - base::Bind(&MidiManagerAlsa::EventLoop, base::Unretained(this)));
|
| + ScheduleEventLoop();
|
| }
|
|
|
| -// static
|
| -std::string MidiManagerAlsa::CardInfo::ExtractManufacturerString(
|
| - 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) {
|
| - // Let's try to determine the manufacturer. Here is the ordered preference
|
| - // in extraction:
|
| - // 1. Vendor name from the USB device iManufacturer string, from
|
| - // the udev property ID_VENDOR_ENC.
|
| - // 2. Vendor name from the udev database (property ID_VENDOR_FROM_DATABASE).
|
| - // 3. Heuristic from ALSA.
|
| -
|
| - // Is the vendor string not just the USB vendor hex id?
|
| - if (udev_id_vendor != udev_id_vendor_id) {
|
| - return udev_id_vendor;
|
| - }
|
| -
|
| - // Is there a vendor string in the hardware database?
|
| - if (!udev_id_vendor_from_database.empty()) {
|
| - return udev_id_vendor_from_database;
|
| - }
|
| -
|
| - // Ok, udev gave us nothing useful, or was unavailable. So try a heuristic.
|
| - // We assume that card longname is in the format of
|
| - // "<manufacturer> <name> at <bus>". Otherwise, we give up to detect
|
| - // a manufacturer name here.
|
| - size_t at_index = alsa_longname.rfind(" at ");
|
| - if (std::string::npos != at_index) {
|
| - size_t name_index = alsa_longname.rfind(alsa_name, at_index - 1);
|
| - if (std::string::npos != name_index)
|
| - return alsa_longname.substr(0, name_index - 1);
|
| +void MidiManagerAlsa::ProcessSingleEvent(snd_seq_event_t* event,
|
| + double timestamp) {
|
| + std::map<int, uint32>::iterator source_it =
|
| + source_map_.find(AddrToInt(&event->source));
|
| + if (source_it != source_map_.end()) {
|
| + uint32 source = source_it->second;
|
| + if (event->type == SND_SEQ_EVENT_SYSEX) {
|
| + // Special! Variable-length sysex.
|
| + ReceiveMidiData(source, static_cast<const uint8*>(event->data.ext.ptr),
|
| + event->data.ext.len, timestamp);
|
| + } else {
|
| + // Otherwise, decode this and send that on.
|
| + unsigned char buf[12];
|
| + long count = snd_midi_event_decode(decoder_, buf, sizeof(buf), event);
|
| + if (count <= 0) {
|
| + if (count != -ENOENT) {
|
| + // ENOENT means that it's not a MIDI message, which is not an
|
| + // error, but other negative values are errors for us.
|
| + VLOG(1) << "snd_midi_event_decoder fails " << snd_strerror(count);
|
| + // TODO(agoode): Record this failure.
|
| + }
|
| + } else {
|
| + ReceiveMidiData(source, buf, count, timestamp);
|
| + }
|
| + }
|
| }
|
| -
|
| - // Failure.
|
| - return "";
|
| }
|
|
|
| MidiManager* MidiManager::Create() {
|
|
|