diff options
author | toyoshim <toyoshim@chromium.org> | 2015-04-03 00:53:39 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-04-03 07:54:53 +0000 |
commit | 863f7cf7589acb1d3e08a8fcc2965bc7fb7713a7 (patch) | |
tree | 32e29ad889642e50699ec33a48639a334c1f42a6 /media | |
parent | 9fdea86ad6c4d3c91b09700715062f69b88fe9a3 (diff) | |
download | chromium_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.gn | 2 | ||||
-rw-r--r-- | media/media.gyp | 2 | ||||
-rw-r--r-- | media/midi/midi_manager_usb.cc | 11 | ||||
-rw-r--r-- | media/midi/midi_manager_usb.h | 4 | ||||
-rw-r--r-- | media/midi/midi_manager_usb_unittest.cc | 10 | ||||
-rw-r--r-- | media/midi/midi_scheduler.cc | 51 | ||||
-rw-r--r-- | media/midi/midi_scheduler.h | 39 |
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_ |