blob: 11f76c07b5362dfabb990af9210c5ffe678d2627 [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <alsa/asoundlib.h>
#include <map>
#include <vector>
#include "base/basictypes.h"
#include "base/gtest_prod_util.h"
#include "base/memory/scoped_ptr.h"
#include "base/synchronization/lock.h"
#include "base/threading/thread.h"
#include "base/values.h"
#include "media/midi/midi_manager.h"
#if defined(USE_UDEV)
#include "device/udev_linux/scoped_udev.h"
#endif // defined(USE_UDEV)
namespace media {
class MEDIA_EXPORT MidiManagerAlsa : public MidiManager {
~MidiManagerAlsa() override;
// MidiManager implementation.
void StartInitialization() override;
void DispatchSendMidiData(MidiManagerClient* client,
uint32 port_index,
const std::vector<uint8>& data,
double timestamp) override;
FRIEND_TEST_ALL_PREFIXES(MidiManagerAlsaTest, ExtractManufacturer);
FRIEND_TEST_ALL_PREFIXES(MidiManagerAlsaTest, JSONPortMetadata);
class AlsaCard {
AlsaCard(const MidiManagerAlsa* outer,
const std::string& alsa_name,
const std::string& alsa_longname,
const std::string& alsa_driver,
int card_index,
int midi_count);
const std::string alsa_name() const;
const std::string alsa_longname() const;
const std::string manufacturer() const;
const std::string alsa_driver() const;
const std::string path() const;
const std::string bus() const;
const std::string vendor_id() const;
const std::string id() const;
const int midi_count() const;
FRIEND_TEST_ALL_PREFIXES(MidiManagerAlsaTest, ExtractManufacturer);
// Extracts the manufacturer using heuristics and a variety of sources.
static std::string 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);
std::string alsa_name_;
std::string alsa_longname_;
std::string manufacturer_;
std::string alsa_driver_;
std::string path_;
std::string bus_;
std::string vendor_id_;
std::string model_id_;
std::string usb_interface_num_;
int midi_count_;
class AlsaPortMetadata {
enum class Type { kInput, kOutput };
AlsaPortMetadata(const std::string& path,
const std::string& bus,
const std::string& id,
const snd_seq_addr_t* address,
const std::string& client_name,
const std::string& port_name,
const std::string& card_name,
const std::string& card_longname,
Type type);
// Gets a Value representation of this object, suitable for serialization.
scoped_ptr<base::Value> Value() const;
// Gets a string version of Value in JSON format.
std::string JSONValue() const;
// Gets an opaque identifier for this object, suitable for using as the id
// field in on the web. Note that this string does not store
// the full state.
std::string OpaqueKey() const;
FRIEND_TEST_ALL_PREFIXES(MidiManagerAlsaTest, JSONPortMetadata);
const std::string path_;
const std::string bus_;
const std::string id_;
const int client_addr_;
const int port_addr_;
const std::string client_name_;
const std::string port_name_;
const std::string card_name_;
const std::string card_longname_;
const Type type_;
// Returns an ordered vector of all the cards with MIDI capabilities.
ScopedVector<AlsaCard> AllMidiCards();
// Enumerate all the ports for initial setup.
void EnumeratePorts();
// An internal callback that runs on MidiSendThread.
void SendMidiData(uint32 port_index,
const std::vector<uint8>& data);
void ScheduleEventLoop();
void EventLoop();
void ProcessSingleEvent(snd_seq_event_t* event, double timestamp);
// ALSA seq handles.
snd_seq_t* in_client_;
snd_seq_t* out_client_;
int out_client_id_;
// One input port, many output ports.
int in_port_;
std::vector<int> out_ports_;
// Mapping from ALSA client:port to our index.
typedef std::map<int, uint32> SourceMap;
SourceMap source_map_;
// ALSA event <-> MIDI coders.
snd_midi_event_t* decoder_;
// udev, for querying hardware devices.
#if defined(USE_UDEV)
device::ScopedUdevPtr udev_;
#endif // defined(USE_UDEV)
base::Thread send_thread_;
base::Thread event_thread_;
bool event_thread_shutdown_; // guarded by shutdown_lock_
base::Lock shutdown_lock_; // guards event_thread_shutdown_
} // namespace media