15d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved. 25d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// found in the LICENSE file. 45d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 55d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "media/midi/midi_manager_alsa.h" 65d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 75d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <alsa/asoundlib.h> 85d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <stdlib.h> 95c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include <algorithm> 105c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include <string> 115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/bind.h" 135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/logging.h" 145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/memory/ref_counted.h" 15f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "base/memory/scoped_vector.h" 165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/message_loop/message_loop.h" 175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/posix/eintr_wrapper.h" 185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/strings/stringprintf.h" 195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/threading/thread.h" 205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/time/time.h" 215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "media/midi/midi_port_info.h" 225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace media { 245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace { 265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 27f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// Per-output buffer. This can be smaller, but then large sysex messages 28f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// will be (harmlessly) split across multiple seq events. This should 29f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// not have any real practical effect, except perhaps to slightly reorder 30f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// realtime messages with respect to sysex. 31f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)const size_t kSendBufferSize = 256; 32f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 33f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// Constants for the capabilities we search for in inputs and outputs. 34f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// See http://www.alsa-project.org/alsa-doc/alsa-lib/seq.html. 35f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)const unsigned int kRequiredInputPortCaps = 36f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_SUBS_READ; 37f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)const unsigned int kRequiredOutputPortCaps = 38f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE; 39f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 40f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)int AddrToInt(const snd_seq_addr_t* addr) { 41f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return (addr->client << 8) | addr->port; 42f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)} 435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 44f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)class CardInfo { 455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) public: 46f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) CardInfo(const std::string name, const std::string manufacturer, 47f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) const std::string driver) 48f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) : name_(name), manufacturer_(manufacturer), driver_(driver) { 495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 50f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) const std::string name_; 51f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) const std::string manufacturer_; 52f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) const std::string driver_; 53f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}; 545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 55f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)} // namespace 565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 57f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)MidiManagerAlsa::MidiManagerAlsa() 58f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) : in_client_(NULL), 59f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) out_client_(NULL), 60f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) out_client_id_(-1), 61f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) in_port_(-1), 62f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) decoder_(NULL), 63f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) send_thread_("MidiSendThread"), 64f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) event_thread_("MidiEventThread"), 65f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) event_thread_shutdown_(false) { 66f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Initialize decoder. 67f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) snd_midi_event_new(0, &decoder_); 68f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) snd_midi_event_no_status(decoder_, 1); 69f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)} 705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 71f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void MidiManagerAlsa::StartInitialization() { 72f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // TODO(agoode): Move off I/O thread. See http://crbug.com/374341. 735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 74f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Create client handles. 75f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) int err = snd_seq_open(&in_client_, "hw", SND_SEQ_OPEN_INPUT, 0); 76f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (err != 0) { 77f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) VLOG(1) << "snd_seq_open fails: " << snd_strerror(err); 78f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return CompleteInitialization(MIDI_INITIALIZATION_ERROR); 795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 80f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) int in_client_id = snd_seq_client_id(in_client_); 81f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) err = snd_seq_open(&out_client_, "hw", SND_SEQ_OPEN_OUTPUT, 0); 82f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (err != 0) { 83f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) VLOG(1) << "snd_seq_open fails: " << snd_strerror(err); 84f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return CompleteInitialization(MIDI_INITIALIZATION_ERROR); 855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 86f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) out_client_id_ = snd_seq_client_id(out_client_); 875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 88f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Name the clients. 89f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) err = snd_seq_set_client_name(in_client_, "Chrome (input)"); 90f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (err != 0) { 91f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) VLOG(1) << "snd_seq_set_client_name fails: " << snd_strerror(err); 92f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return CompleteInitialization(MIDI_INITIALIZATION_ERROR); 935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 94f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) err = snd_seq_set_client_name(out_client_, "Chrome (output)"); 95f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (err != 0) { 96f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) VLOG(1) << "snd_seq_set_client_name fails: " << snd_strerror(err); 97f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return CompleteInitialization(MIDI_INITIALIZATION_ERROR); 985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 100f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Create input port. 101f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) in_port_ = snd_seq_create_simple_port(in_client_, NULL, 102f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) SND_SEQ_PORT_CAP_WRITE | 103f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) SND_SEQ_PORT_CAP_NO_EXPORT, 104f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) SND_SEQ_PORT_TYPE_MIDI_GENERIC | 105f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) SND_SEQ_PORT_TYPE_APPLICATION); 106f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (in_port_ < 0) { 107f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) VLOG(1) << "snd_seq_create_simple_port fails: " << snd_strerror(in_port_); 108f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return CompleteInitialization(MIDI_INITIALIZATION_ERROR); 109f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 1105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 111f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Subscribe to the announce port. 112f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) snd_seq_port_subscribe_t* subs; 113f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) snd_seq_port_subscribe_alloca(&subs); 114f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) snd_seq_addr_t announce_sender; 115f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) snd_seq_addr_t announce_dest; 116f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) announce_sender.client = SND_SEQ_CLIENT_SYSTEM; 117f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) announce_sender.port = SND_SEQ_PORT_SYSTEM_ANNOUNCE; 118f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) announce_dest.client = in_client_id; 119f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) announce_dest.port = in_port_; 120f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) snd_seq_port_subscribe_set_sender(subs, &announce_sender); 121f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) snd_seq_port_subscribe_set_dest(subs, &announce_dest); 122f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) err = snd_seq_subscribe_port(in_client_, subs); 123f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (err != 0) { 124f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) VLOG(1) << "snd_seq_subscribe_port on the announce port fails: " 125f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) << snd_strerror(err); 126f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return CompleteInitialization(MIDI_INITIALIZATION_ERROR); 127f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 1285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 129f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Use a heuristic to extract the list of manufacturers for the hardware MIDI 130f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // devices. This won't work for all devices. It is also brittle until 131f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // hotplug is implemented. (See http://crbug.com/279097.) 132f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // TODO(agoode): Make manufacturer extraction simple and reliable. 133f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // http://crbug.com/377250. 134f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) ScopedVector<CardInfo> cards; 1355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) snd_ctl_card_info_t* card; 1365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) snd_rawmidi_info_t* midi_out; 1375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) snd_rawmidi_info_t* midi_in; 1385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) snd_ctl_card_info_alloca(&card); 1395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) snd_rawmidi_info_alloca(&midi_out); 1405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) snd_rawmidi_info_alloca(&midi_in); 1415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) for (int index = -1; !snd_card_next(&index) && index >= 0; ) { 1425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const std::string id = base::StringPrintf("hw:CARD=%i", index); 1435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) snd_ctl_t* handle; 1445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) int err = snd_ctl_open(&handle, id.c_str(), 0); 1455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (err != 0) { 146a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) VLOG(1) << "snd_ctl_open fails: " << snd_strerror(err); 1475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) continue; 1485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) err = snd_ctl_card_info(handle, card); 1505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (err != 0) { 151a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) VLOG(1) << "snd_ctl_card_info fails: " << snd_strerror(err); 1525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) snd_ctl_close(handle); 1535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) continue; 1545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 155f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Enumerate any rawmidi devices (not subdevices) and extract CardInfo. 1565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) for (int device = -1; 157f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) !snd_ctl_rawmidi_next_device(handle, &device) && device >= 0; ) { 1585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) bool output; 1595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) bool input; 1605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) snd_rawmidi_info_set_device(midi_out, device); 1615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) snd_rawmidi_info_set_subdevice(midi_out, 0); 1625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) snd_rawmidi_info_set_stream(midi_out, SND_RAWMIDI_STREAM_OUTPUT); 1635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) output = snd_ctl_rawmidi_info(handle, midi_out) == 0; 1645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) snd_rawmidi_info_set_device(midi_in, device); 1655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) snd_rawmidi_info_set_subdevice(midi_in, 0); 1665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) snd_rawmidi_info_set_stream(midi_in, SND_RAWMIDI_STREAM_INPUT); 1675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) input = snd_ctl_rawmidi_info(handle, midi_in) == 0; 1685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (!output && !input) 1695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) continue; 170f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 171f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) snd_rawmidi_info_t* midi = midi_out ? midi_out : midi_in; 172f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) const std::string name = snd_rawmidi_info_get_name(midi); 173f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // We assume that card longname is in the format of 174f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // "<manufacturer> <name> at <bus>". Otherwise, we give up to detect 175f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // a manufacturer name here. 176f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) std::string manufacturer; 177f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) const std::string card_name = snd_ctl_card_info_get_longname(card); 178f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) size_t at_index = card_name.rfind(" at "); 179f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (std::string::npos != at_index) { 180f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) size_t name_index = card_name.rfind(name, at_index - 1); 181f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (std::string::npos != name_index) 182f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) manufacturer = card_name.substr(0, name_index - 1); 1835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 184f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) const std::string driver = snd_ctl_card_info_get_driver(card); 185f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) cards.push_back(new CardInfo(name, manufacturer, driver)); 186f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 187f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 188f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 189f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Enumerate all ports in all clients. 190f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) snd_seq_client_info_t* client_info; 191f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) snd_seq_client_info_alloca(&client_info); 192f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) snd_seq_port_info_t* port_info; 193f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) snd_seq_port_info_alloca(&port_info); 194f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 195f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) snd_seq_client_info_set_client(client_info, -1); 196f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Enumerate clients. 197f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) uint32 current_input = 0; 198f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) unsigned int current_card = 0; 199f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) while (!snd_seq_query_next_client(in_client_, client_info)) { 200f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) int client_id = snd_seq_client_info_get_client(client_info); 201f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if ((client_id == in_client_id) || (client_id == out_client_id_)) { 202f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Skip our own clients. 203f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) continue; 204f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 205f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) const std::string client_name = snd_seq_client_info_get_name(client_info); 206f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) snd_seq_port_info_set_client(port_info, client_id); 207f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) snd_seq_port_info_set_port(port_info, -1); 208f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 209f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) std::string manufacturer; 210f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) std::string driver; 211f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // In the current Alsa kernel implementation, hardware clients match the 212f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // cards in the same order. 213f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if ((snd_seq_client_info_get_type(client_info) == SND_SEQ_KERNEL_CLIENT) && 214f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) (current_card < cards.size())) { 215f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) const CardInfo* info = cards[current_card]; 216f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (info->name_ == client_name) { 217f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) manufacturer = info->manufacturer_; 218f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) driver = info->driver_; 219f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) current_card++; 2205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 221f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 222f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Enumerate ports. 223f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) while (!snd_seq_query_next_port(in_client_, port_info)) { 224f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) unsigned int port_type = snd_seq_port_info_get_type(port_info); 225f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (port_type & SND_SEQ_PORT_TYPE_MIDI_GENERIC) { 226f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) const snd_seq_addr_t* addr = snd_seq_port_info_get_addr(port_info); 227f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) const std::string name = snd_seq_port_info_get_name(port_info); 228f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) const std::string id = base::StringPrintf("%d:%d %s", 229f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) addr->client, 230f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) addr->port, 231f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) name.c_str()); 232f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) std::string version; 233f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (driver != "") { 234f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) version = driver + " / "; 235f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 236f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) version += base::StringPrintf("ALSA library version %d.%d.%d", 237f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) SND_LIB_MAJOR, 238f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) SND_LIB_MINOR, 239f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) SND_LIB_SUBMINOR); 240f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) unsigned int caps = snd_seq_port_info_get_capability(port_info); 241f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if ((caps & kRequiredInputPortCaps) == kRequiredInputPortCaps) { 242f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Subscribe to this port. 243f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) const snd_seq_addr_t* sender = snd_seq_port_info_get_addr(port_info); 244f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) snd_seq_addr_t dest; 245f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) dest.client = snd_seq_client_id(in_client_); 246f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) dest.port = in_port_; 247f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) snd_seq_port_subscribe_set_sender(subs, sender); 248f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) snd_seq_port_subscribe_set_dest(subs, &dest); 249f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) err = snd_seq_subscribe_port(in_client_, subs); 250f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (err != 0) { 251f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) VLOG(1) << "snd_seq_subscribe_port fails: " << snd_strerror(err); 252f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } else { 253f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) source_map_[AddrToInt(sender)] = current_input++; 254f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) AddInputPort(MidiPortInfo(id, manufacturer, name, version)); 255f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 256f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 257f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if ((caps & kRequiredOutputPortCaps) == kRequiredOutputPortCaps) { 258f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Create a port for us to send on. 259f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) int out_port = 260f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) snd_seq_create_simple_port(out_client_, NULL, 261f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) SND_SEQ_PORT_CAP_READ | 262f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) SND_SEQ_PORT_CAP_NO_EXPORT, 263f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) SND_SEQ_PORT_TYPE_MIDI_GENERIC | 264f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) SND_SEQ_PORT_TYPE_APPLICATION); 265f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (out_port < 0) { 266f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) VLOG(1) << "snd_seq_create_simple_port fails: " 267f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) << snd_strerror(out_port); 268f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Skip this output port for now. 269f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) continue; 270f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 271f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 272f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Activate port subscription. 273f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) snd_seq_addr_t sender; 274f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) const snd_seq_addr_t* dest = snd_seq_port_info_get_addr(port_info); 275f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) sender.client = snd_seq_client_id(out_client_); 276f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) sender.port = out_port; 277f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) snd_seq_port_subscribe_set_sender(subs, &sender); 278f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) snd_seq_port_subscribe_set_dest(subs, dest); 279f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) err = snd_seq_subscribe_port(out_client_, subs); 280f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (err != 0) { 281f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) VLOG(1) << "snd_seq_subscribe_port fails: " << snd_strerror(err); 282f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) snd_seq_delete_simple_port(out_client_, out_port); 283f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } else { 284f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) snd_midi_event_t* encoder; 285f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) snd_midi_event_new(kSendBufferSize, &encoder); 286f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) encoders_.push_back(encoder); 287f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) out_ports_.push_back(out_port); 288f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) AddOutputPort(MidiPortInfo(id, manufacturer, name, version)); 289f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 290f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 2915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 2925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 2935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 2945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 295f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) event_thread_.Start(); 296f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) event_thread_.message_loop()->PostTask( 297f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) FROM_HERE, 298f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) base::Bind(&MidiManagerAlsa::EventReset, base::Unretained(this))); 299f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 300f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) CompleteInitialization(MIDI_OK); 3015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 3025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 3035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)MidiManagerAlsa::~MidiManagerAlsa() { 304f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Tell the event thread it will soon be time to shut down. This gives 305f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // us assurance the thread will stop in case the SND_SEQ_EVENT_CLIENT_EXIT 306f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // message is lost. 307f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) { 308f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) base::AutoLock lock(shutdown_lock_); 309f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) event_thread_shutdown_ = true; 310f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 3115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 312f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Stop the send thread. 313f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) send_thread_.Stop(); 314f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 315f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Close the out client. This will trigger the event thread to stop, 316f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // because of SND_SEQ_EVENT_CLIENT_EXIT. 317f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (out_client_) 318f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) snd_seq_close(out_client_); 319f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 320f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Wait for the event thread to stop. 3215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) event_thread_.Stop(); 3225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 323f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Close the in client. 324f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (in_client_) 325f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) snd_seq_close(in_client_); 326f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 327f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Free the decoder. 328f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) snd_midi_event_free(decoder_); 329f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 330f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Free the encoders. 331f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) for (EncoderList::iterator i = encoders_.begin(); i != encoders_.end(); ++i) 332f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) snd_midi_event_free(*i); 333f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)} 334f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 335f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void MidiManagerAlsa::SendMidiData(uint32 port_index, 336f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) const std::vector<uint8>& data) { 337f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) DCHECK(send_thread_.message_loop_proxy()->BelongsToCurrentThread()); 338f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 339f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) snd_midi_event_t* encoder = encoders_[port_index]; 340f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) for (unsigned int i = 0; i < data.size(); i++) { 341f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) snd_seq_event_t event; 342f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) int result = snd_midi_event_encode_byte(encoder, data[i], &event); 343f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (result == 1) { 344f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Full event, send it. 345f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) snd_seq_ev_set_source(&event, out_ports_[port_index]); 346f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) snd_seq_ev_set_subs(&event); 347f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) snd_seq_ev_set_direct(&event); 348f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) snd_seq_event_output_direct(out_client_, &event); 349f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 3505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 3515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 3525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 3535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void MidiManagerAlsa::DispatchSendMidiData(MidiManagerClient* client, 3545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) uint32 port_index, 3555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const std::vector<uint8>& data, 3565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) double timestamp) { 357f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (out_ports_.size() <= port_index) 3585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return; 3595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 360f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Not correct right now. http://crbug.com/374341. 361f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (!send_thread_.IsRunning()) 362f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) send_thread_.Start(); 363f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 3645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::TimeDelta delay; 3655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (timestamp != 0.0) { 3665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::TimeTicks time_to_send = 3675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::TimeTicks() + base::TimeDelta::FromMicroseconds( 3685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) timestamp * base::Time::kMicrosecondsPerSecond); 3695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) delay = std::max(time_to_send - base::TimeTicks::Now(), base::TimeDelta()); 3705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 3715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 3725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) send_thread_.message_loop()->PostDelayedTask( 3735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) FROM_HERE, 374f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) base::Bind(&MidiManagerAlsa::SendMidiData, base::Unretained(this), 375f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) port_index, data), delay); 376f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 377f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Acknowledge send. 378f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) send_thread_.message_loop()->PostTask( 379f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) FROM_HERE, 380f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) base::Bind(&MidiManagerClient::AccumulateMidiBytesSent, 381f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) base::Unretained(client), data.size())); 3825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 3835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 3845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void MidiManagerAlsa::EventReset() { 3855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) event_thread_.message_loop()->PostTask( 3865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) FROM_HERE, 3875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::Bind(&MidiManagerAlsa::EventLoop, base::Unretained(this))); 3885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 3895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 3905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void MidiManagerAlsa::EventLoop() { 3915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Read available incoming MIDI data. 392f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) snd_seq_event_t* event; 393f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) int err = snd_seq_event_input(in_client_, &event); 394f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) double timestamp = 395f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) (base::TimeTicks::HighResNow() - base::TimeTicks()).InSecondsF(); 396f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (err == -ENOSPC) { 397f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) VLOG(1) << "snd_seq_event_input detected buffer overrun"; 398f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 399f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // We've lost events: check another way to see if we need to shut down. 400f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) base::AutoLock lock(shutdown_lock_); 401f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (event_thread_shutdown_) { 402f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return; 403f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 404f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } else if (err < 0) { 405f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) VLOG(1) << "snd_seq_event_input fails: " << snd_strerror(err); 406f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return; 407f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } else { 408f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Check for disconnection of out client. This means "shut down". 409f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (event->source.client == SND_SEQ_CLIENT_SYSTEM && 410f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) event->source.port == SND_SEQ_PORT_SYSTEM_ANNOUNCE && 411f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) event->type == SND_SEQ_EVENT_CLIENT_EXIT && 412f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) event->data.addr.client == out_client_id_) { 413f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) return; 4145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 415f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 416f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) std::map<int, uint32>::iterator source_it = 417f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) source_map_.find(AddrToInt(&event->source)); 418f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (source_it != source_map_.end()) { 419f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) uint32 source = source_it->second; 420f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (event->type == SND_SEQ_EVENT_SYSEX) { 421f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Special! Variable-length sysex. 422f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) ReceiveMidiData(source, static_cast<const uint8*>(event->data.ext.ptr), 423f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) event->data.ext.len, 424f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) timestamp); 425f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } else { 426f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // Otherwise, decode this and send that on. 427f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) unsigned char buf[12]; 428f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) long count = snd_midi_event_decode(decoder_, buf, sizeof(buf), event); 429f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (count <= 0) { 430f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) if (count != -ENOENT) { 431f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // ENOENT means that it's not a MIDI message, which is not an 432f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) // error, but other negative values are errors for us. 433f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) VLOG(1) << "snd_midi_event_decoder fails " << snd_strerror(count); 434f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 435f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } else { 436f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) ReceiveMidiData(source, buf, count, timestamp); 437f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 438f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) } 4395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 4405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 4415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 4425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Do again. 4435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) event_thread_.message_loop()->PostTask( 4445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) FROM_HERE, 4455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::Bind(&MidiManagerAlsa::EventLoop, base::Unretained(this))); 4465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 4475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 4485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)MidiManager* MidiManager::Create() { 4495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return new MidiManagerAlsa(); 4505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 4515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 4525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} // namespace media 453