summaryrefslogtreecommitdiffstats
path: root/media
diff options
context:
space:
mode:
authortoyoshim <toyoshim@chromium.org>2015-04-03 00:53:39 -0700
committerCommit bot <commit-bot@chromium.org>2015-04-03 07:54:53 +0000
commit863f7cf7589acb1d3e08a8fcc2965bc7fb7713a7 (patch)
tree32e29ad889642e50699ec33a48639a334c1f42a6 /media
parent9fdea86ad6c4d3c91b09700715062f69b88fe9a3 (diff)
downloadchromium_src-863f7cf7589acb1d3e08a8fcc2965bc7fb7713a7.zip
chromium_src-863f7cf7589acb1d3e08a8fcc2965bc7fb7713a7.tar.gz
chromium_src-863f7cf7589acb1d3e08a8fcc2965bc7fb7713a7.tar.bz2
Web MIDI: add MidiScheduler for send() with timestamp
Add MidiScheduler as a common timestamp handling class for all Web MIDI backend implementations. In this patch, Android backend switches to use the scheduler to handle timestamp. BUG=467442, 303596 Review URL: https://codereview.chromium.org/1052983002 Cr-Commit-Position: refs/heads/master@{#323674}
Diffstat (limited to 'media')
-rw-r--r--media/BUILD.gn2
-rw-r--r--media/media.gyp2
-rw-r--r--media/midi/midi_manager_usb.cc11
-rw-r--r--media/midi/midi_manager_usb.h4
-rw-r--r--media/midi/midi_manager_usb_unittest.cc10
-rw-r--r--media/midi/midi_scheduler.cc51
-rw-r--r--media/midi/midi_scheduler.h39
7 files changed, 115 insertions, 4 deletions
diff --git a/media/BUILD.gn b/media/BUILD.gn
index cf26159..c9dc100 100644
--- a/media/BUILD.gn
+++ b/media/BUILD.gn
@@ -193,6 +193,8 @@ component("media") {
"midi/midi_message_util.h",
"midi/midi_port_info.cc",
"midi/midi_port_info.h",
+ "midi/midi_scheduler.cc",
+ "midi/midi_scheduler.h",
"midi/usb_midi_descriptor_parser.cc",
"midi/usb_midi_descriptor_parser.h",
"midi/usb_midi_device.h",
diff --git a/media/media.gyp b/media/media.gyp
index 26ba789..8e44915 100644
--- a/media/media.gyp
+++ b/media/media.gyp
@@ -532,6 +532,8 @@
'midi/midi_message_util.h',
'midi/midi_port_info.cc',
'midi/midi_port_info.h',
+ 'midi/midi_scheduler.cc',
+ 'midi/midi_scheduler.h',
'midi/usb_midi_descriptor_parser.cc',
'midi/usb_midi_descriptor_parser.h',
'midi/usb_midi_device.h',
diff --git a/media/midi/midi_manager_usb.cc b/media/midi/midi_manager_usb.cc
index eab41da..2571727 100644
--- a/media/midi/midi_manager_usb.cc
+++ b/media/midi/midi_manager_usb.cc
@@ -9,6 +9,7 @@
#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_loop.h"
#include "base/strings/stringprintf.h"
+#include "media/midi/midi_scheduler.h"
#include "media/midi/usb_midi_descriptor_parser.h"
#include "media/midi/usb_midi_device.h"
#include "media/midi/usb_midi_input_stream.h"
@@ -32,6 +33,7 @@ void MidiManagerUsb::StartInitialization() {
void MidiManagerUsb::Initialize(
base::Callback<void(MidiResult result)> callback) {
initialize_callback_ = callback;
+ scheduler_.reset(new MidiScheduler);
// This is safe because EnumerateDevices cancels the operation on destruction.
device_factory_->EnumerateDevices(
this,
@@ -48,8 +50,13 @@ void MidiManagerUsb::DispatchSendMidiData(MidiManagerClient* client,
// in the valid range.
return;
}
- output_streams_[port_index]->Send(data);
- client->AccumulateMidiBytesSent(data.size());
+ // output_streams_[port_index] is alive unless MidiManagerUsb is deleted.
+ // The task posted to the MidiScheduler will be disposed safely on deleting
+ // the scheduler.
+ scheduler_->PostSendDataTask(
+ client, data.size(), timestamp,
+ base::Bind(&UsbMidiOutputStream::Send,
+ base::Unretained(output_streams_[port_index]), data));
}
void MidiManagerUsb::ReceiveUsbMidiData(UsbMidiDevice* device,
diff --git a/media/midi/midi_manager_usb.h b/media/midi/midi_manager_usb.h
index ea9b589..417aac5 100644
--- a/media/midi/midi_manager_usb.h
+++ b/media/midi/midi_manager_usb.h
@@ -23,6 +23,8 @@
namespace media {
+class MidiScheduler;
+
// MidiManager for USB-MIDI.
class MEDIA_EXPORT MidiManagerUsb : public MidiManager,
public UsbMidiDeviceDelegate,
@@ -81,6 +83,8 @@ class MEDIA_EXPORT MidiManagerUsb : public MidiManager,
// A map from <endpoint_number, cable_number> to the index of input jacks.
base::hash_map<std::pair<int, int>, size_t> input_jack_dictionary_;
+ scoped_ptr<MidiScheduler> scheduler_;
+
DISALLOW_COPY_AND_ASSIGN(MidiManagerUsb);
};
diff --git a/media/midi/midi_manager_usb_unittest.cc b/media/midi/midi_manager_usb_unittest.cc
index 0afb98b..b699576 100644
--- a/media/midi/midi_manager_usb_unittest.cc
+++ b/media/midi/midi_manager_usb_unittest.cc
@@ -354,12 +354,18 @@ TEST_F(MidiManagerUsbTest, Send) {
ASSERT_EQ(2u, manager_->output_streams().size());
manager_->DispatchSendMidiData(&client, 1, ToVector(data), 0);
+ // Since UsbMidiDevice::Send is posted as a task, RunLoop should run to
+ // invoke the task.
+ // TODO(crbug.com/467442): AccumulateMidiBytesSent is recorded before
+ // UsbMidiDevice is invoked for now, but this should be after the invocation.
+ base::RunLoop run_loop;
+ run_loop.RunUntilIdle();
EXPECT_EQ("UsbMidiDevice::GetDescriptor\n"
+ "MidiManagerClient::AccumulateMidiBytesSent size = 7\n"
"UsbMidiDevice::Send endpoint = 2 data = "
"0x19 0x90 0x45 0x7f "
"0x14 0xf0 0x00 0x01 "
- "0x15 0xf7 0x00 0x00\n"
- "MidiManagerClient::AccumulateMidiBytesSent size = 7\n",
+ "0x15 0xf7 0x00 0x00\n",
logger_.TakeLog());
}
diff --git a/media/midi/midi_scheduler.cc b/media/midi/midi_scheduler.cc
new file mode 100644
index 0000000..cc93733
--- /dev/null
+++ b/media/midi/midi_scheduler.cc
@@ -0,0 +1,51 @@
+// Copyright 2015 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_scheduler.h"
+
+#include "base/bind.h"
+#include "base/message_loop/message_loop.h"
+#include "base/time/time.h"
+#include "media/midi/midi_manager.h"
+
+namespace media {
+
+MidiScheduler::MidiScheduler() : weak_factory_(this) {
+}
+
+MidiScheduler::~MidiScheduler() {
+}
+
+// TODO(crbug.com/467442): Use CancelableTaskTracker once it supports
+// DelayedTask.
+void MidiScheduler::PostSendDataTask(MidiManagerClient* client,
+ size_t length,
+ double timestamp,
+ const base::Closure& closure) {
+ DCHECK(client);
+
+ const base::Closure& weak_closure = base::Bind(
+ &MidiScheduler::InvokeClosure, weak_factory_.GetWeakPtr(), closure);
+
+ 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());
+ }
+ base::MessageLoop::current()->task_runner()->PostDelayedTask(
+ FROM_HERE, weak_closure, delay);
+
+ // TODO(crbug.com/467442): AccumulateMidiBytesSent should be called in
+ // InvokeClosure. But for now, we call it here since |client| may be deleted
+ // at that time.
+ client->AccumulateMidiBytesSent(length);
+}
+
+void MidiScheduler::InvokeClosure(const base::Closure& closure) {
+ closure.Run();
+}
+
+} // namespace media
diff --git a/media/midi/midi_scheduler.h b/media/midi/midi_scheduler.h
new file mode 100644
index 0000000..3cb8433
--- /dev/null
+++ b/media/midi/midi_scheduler.h
@@ -0,0 +1,39 @@
+// Copyright 2015 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_SCHEDULER_H_
+#define MEDIA_MIDI_MIDI_SCHEDULER_H_
+
+#include "base/callback.h"
+#include "base/memory/weak_ptr.h"
+
+namespace media {
+
+class MidiManagerClient;
+
+// TODO(crbug.com/467442): Make tasks cancelable per client.
+class MidiScheduler final {
+ public:
+ MidiScheduler();
+ ~MidiScheduler();
+
+ // Post |closure| to the current message loop safely. The |closure| will not
+ // be invoked after MidiScheduler is deleted. AccumulateMidiBytesSent() of
+ // |client| is called internally.
+ void PostSendDataTask(MidiManagerClient* client,
+ size_t length,
+ double timestamp,
+ const base::Closure& closure);
+
+ private:
+ void InvokeClosure(const base::Closure& closure);
+
+ base::WeakPtrFactory<MidiScheduler> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(MidiScheduler);
+};
+
+} // namespace media
+
+#endif // MEDIA_MIDI_MIDI_SCHEDULER_H_