From b90727df54af9be1037095be8f046d93e6d922dc Mon Sep 17 00:00:00 2001 From: "toyoshim@chromium.org" Date: Wed, 18 Dec 2013 08:17:16 +0000 Subject: Web MIDI: minimum support for Linux and Chrome OS This change enables Web MIDI API on Linux and Chrome OS. Only Sending functionality works with this first experimental change. BUG=303601 Review URL: https://codereview.chromium.org/111443005 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@241524 0039d316-1c4b-4281-b951-d872f2087c98 --- chrome/browser/about_flags.cc | 2 +- media/media.gyp | 2 + media/midi/midi_manager.cc | 4 +- media/midi/midi_manager_linux.cc | 139 +++++++++++++++++++++++++++++++++++++++ media/midi/midi_manager_linux.h | 39 +++++++++++ 5 files changed, 183 insertions(+), 3 deletions(-) create mode 100644 media/midi/midi_manager_linux.cc create mode 100644 media/midi/midi_manager_linux.h diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index a263b88..d6f9628 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc @@ -1709,7 +1709,7 @@ const Experiment kExperiments[] = { "enable-web-midi", IDS_FLAGS_ENABLE_WEB_MIDI_NAME, IDS_FLAGS_ENABLE_WEB_MIDI_DESCRIPTION, - kOsMac | kOsWin, + kOsMac | kOsWin | kOsLinux | kOsCrOS, SINGLE_VALUE_TYPE(switches::kEnableWebMIDI) }, { diff --git a/media/media.gyp b/media/media.gyp index fb844de..d70938d 100644 --- a/media/media.gyp +++ b/media/media.gyp @@ -407,6 +407,8 @@ 'filters/wsola_internals.h', 'midi/midi_manager.cc', 'midi/midi_manager.h', + 'midi/midi_manager_linux.cc', + 'midi/midi_manager_linux.h', 'midi/midi_manager_mac.cc', 'midi/midi_manager_mac.h', 'midi/midi_message_queue.cc', diff --git a/media/midi/midi_manager.cc b/media/midi/midi_manager.cc index 6d3f1d3..5ef103f 100644 --- a/media/midi/midi_manager.cc +++ b/media/midi/midi_manager.cc @@ -9,8 +9,8 @@ namespace media { -#if !defined(OS_MACOSX) && !defined(OS_WIN) -// TODO(crogers): implement MIDIManager for other platforms. +#if defined(OS_ANDROID) || defined(OS_IOS) +// TODO(toyoshim): implement MIDIManager for other platforms. MIDIManager* MIDIManager::Create() { return NULL; } diff --git a/media/midi/midi_manager_linux.cc b/media/midi/midi_manager_linux.cc new file mode 100644 index 0000000..712d53d --- /dev/null +++ b/media/midi/midi_manager_linux.cc @@ -0,0 +1,139 @@ +// Copyright 2013 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 "media/midi/midi_manager_linux.h" + +#include +#include +#include +#include +#include + +#include "base/bind.h" +#include "base/debug/trace_event.h" +#include "base/files/file.h" +#include "base/files/file_enumerator.h" +#include "base/files/file_path.h" +#include "base/memory/ref_counted.h" +#include "base/message_loop/message_loop.h" +#include "base/strings/string_util.h" +#include "base/threading/thread.h" +#include "media/midi/midi_port_info.h" + +namespace media { +namespace { + +const char kDevSnd[] = "/dev/snd"; +const char kMIDIPattern[] = "midi*"; +const char kUnknown[] = "[unknown]"; + +} // namespace + +class MIDIManagerLinux::MIDIDeviceInfo + : public base::RefCounted { + public: + MIDIDeviceInfo(MIDIManagerLinux* manager, base::FilePath path) + : flags_(0) { + file_ = base::File(path, + base::File::FLAG_OPEN | + base::File::FLAG_READ | + base::File::FLAG_WRITE); + if (file_.error() != base::File::FILE_OK) + return; + + struct snd_rawmidi_info info = {}; + if (ioctl(file_.GetPlatformFile(), SNDRV_RAWMIDI_IOCTL_INFO, &info)) + return; + + flags_ = info.flags; + const char* name = reinterpret_cast(&info.name[0]); + port_info_ = MIDIPortInfo(path.value(), kUnknown, name, kUnknown); + } + + void Send(MIDIManagerClient* client, const std::vector& data) { + if (!file_.IsValid()) + return; + file_.WriteAtCurrentPos(reinterpret_cast(&data[0]), + data.size()); + base::MessageLoop::current()->PostTask( + FROM_HERE, + base::Bind(&MIDIManagerClient::AccumulateMIDIBytesSent, + base::Unretained(client), data.size())); + } + + bool HasInputPort() const { return flags_ & SNDRV_RAWMIDI_INFO_INPUT; } + bool HasOutputPort() const { return flags_ & SNDRV_RAWMIDI_INFO_OUTPUT; } + const MIDIPortInfo& GetMIDIPortInfo() const { return port_info_; } + + private: + friend class base::RefCounted; + virtual ~MIDIDeviceInfo() {} + + base::File file_; + int flags_; + MIDIPortInfo port_info_; + + DISALLOW_COPY_AND_ASSIGN(MIDIDeviceInfo); +}; + +MIDIManagerLinux::MIDIManagerLinux() + : send_thread_("MIDISendThread") { +} + +bool MIDIManagerLinux::Initialize() { + TRACE_EVENT0("midi", "MIDIManagerMac::Initialize"); + + base::FilePath path(kDevSnd); + base::FileEnumerator enumerator(path, false, base::FileEnumerator::FILES, + FILE_PATH_LITERAL(kMIDIPattern)); + for (base::FilePath name = enumerator.Next(); + !name.empty(); + name = enumerator.Next()) { + scoped_refptr device = new MIDIDeviceInfo(this, name); + if (device->HasInputPort()) { + in_devices_.push_back(device); + AddInputPort(device->GetMIDIPortInfo()); + } + if (device->HasOutputPort()) { + out_devices_.push_back(device); + AddOutputPort(device->GetMIDIPortInfo()); + } + } + return true; +} + +MIDIManagerLinux::~MIDIManagerLinux() { + send_thread_.Stop(); +} + +void MIDIManagerLinux::DispatchSendMIDIData(MIDIManagerClient* client, + uint32 port_index, + const std::vector& data, + double timestamp) { + if (out_devices_.size() <= port_index) + return; + + 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()); + } + + if (!send_thread_.IsRunning()) + send_thread_.Start(); + + scoped_refptr device = out_devices_[port_index]; + send_thread_.message_loop()->PostDelayedTask( + FROM_HERE, + base::Bind(&MIDIDeviceInfo::Send, device, client, data), + delay); +} + +MIDIManager* MIDIManager::Create() { + return new MIDIManagerLinux(); +} + +} // namespace media diff --git a/media/midi/midi_manager_linux.h b/media/midi/midi_manager_linux.h new file mode 100644 index 0000000..f033f14 --- /dev/null +++ b/media/midi/midi_manager_linux.h @@ -0,0 +1,39 @@ +// Copyright 2013 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. + +#ifndef MEDIA_MIDI_MIDI_MANAGER_LINUX_H_ +#define MEDIA_MIDI_MIDI_MANAGER_LINUX_H_ + +#include + +#include "base/basictypes.h" +#include "base/memory/scoped_ptr.h" +#include "base/threading/thread.h" +#include "media/midi/midi_manager.h" + +namespace media { + +class MIDIManagerLinux : public MIDIManager { + public: + MIDIManagerLinux(); + virtual ~MIDIManagerLinux(); + + // MIDIManager implementation. + virtual bool Initialize() OVERRIDE; + virtual void DispatchSendMIDIData(MIDIManagerClient* client, + uint32 port_index, + const std::vector& data, + double timestamp) OVERRIDE; + + private: + class MIDIDeviceInfo; + std::vector > in_devices_; + std::vector > out_devices_; + base::Thread send_thread_; + DISALLOW_COPY_AND_ASSIGN(MIDIManagerLinux); +}; + +} // namespace media + +#endif // MEDIA_MIDI_MIDI_MANAGER_LINUX_H_ -- cgit v1.1