Index: content/renderer/media/midi_message_filter.cc |
diff --git a/content/renderer/media/midi_message_filter.cc b/content/renderer/media/midi_message_filter.cc |
index 165451a50f695fc34bb7cc8d33d56d5f07a0bb7c..8f08ff4dd356f655bf96d8c093c6771c61bb43f8 100644 |
--- a/content/renderer/media/midi_message_filter.cc |
+++ b/content/renderer/media/midi_message_filter.cc |
@@ -4,6 +4,8 @@ |
#include "content/renderer/media/midi_message_filter.h" |
+#include <algorithm> |
+ |
#include "base/bind.h" |
#include "base/debug/trace_event.h" |
#include "base/message_loop/message_loop_proxy.h" |
@@ -22,17 +24,80 @@ static const size_t kMaxUnacknowledgedBytesSent = 10 * 1024 * 1024; // 10 MB. |
namespace content { |
+// TODO(crbug.com/425389): Rewrite this class as a RenderFrameObserver. |
MidiMessageFilter::MidiMessageFilter( |
const scoped_refptr<base::MessageLoopProxy>& io_message_loop) |
: sender_(NULL), |
io_message_loop_(io_message_loop), |
main_message_loop_(base::MessageLoopProxy::current()), |
- next_available_id_(0), |
- unacknowledged_bytes_sent_(0) { |
+ session_result_(media::MIDI_NOT_INITIALIZED), |
+ unacknowledged_bytes_sent_(0u) { |
} |
MidiMessageFilter::~MidiMessageFilter() {} |
+void MidiMessageFilter::AddClient(blink::WebMIDIAccessorClient* client) { |
+ DCHECK(main_message_loop_->BelongsToCurrentThread()); |
+ TRACE_EVENT0("midi", "MidiMessageFilter::AddClient"); |
+ clients_waiting_session_queue_.push_back(client); |
+ if (session_result_ != media::MIDI_NOT_INITIALIZED) { |
+ HandleClientAdded(session_result_); |
+ } else if (clients_waiting_session_queue_.size() == 1u) { |
+ io_message_loop_->PostTask(FROM_HERE, |
+ base::Bind(&MidiMessageFilter::StartSessionOnIOThread, this)); |
+ } |
+} |
+ |
+void MidiMessageFilter::RemoveClient(blink::WebMIDIAccessorClient* client) { |
+ DCHECK(main_message_loop_->BelongsToCurrentThread()); |
+ clients_.erase(client); |
+ ClientsQueue::iterator it = std::find(clients_waiting_session_queue_.begin(), |
+ clients_waiting_session_queue_.end(), |
+ client); |
+ if (it != clients_waiting_session_queue_.end()) |
+ clients_waiting_session_queue_.erase(it); |
+ if (clients_.empty() && clients_waiting_session_queue_.empty()) { |
+ session_result_ = media::MIDI_NOT_INITIALIZED; |
+ io_message_loop_->PostTask(FROM_HERE, |
+ base::Bind(&MidiMessageFilter::EndSessionOnIOThread, this)); |
+ } |
+} |
+ |
+void MidiMessageFilter::SendMidiData(uint32 port, |
+ const uint8* data, |
+ size_t length, |
+ double timestamp) { |
+ DCHECK(main_message_loop_->BelongsToCurrentThread()); |
+ if ((kMaxUnacknowledgedBytesSent - unacknowledged_bytes_sent_) < length) { |
+ // TODO(toyoshim): buffer up the data to send at a later time. |
+ // For now we're just dropping these bytes on the floor. |
+ return; |
+ } |
+ |
+ unacknowledged_bytes_sent_ += length; |
+ std::vector<uint8> v(data, data + length); |
+ io_message_loop_->PostTask(FROM_HERE, base::Bind( |
+ &MidiMessageFilter::SendMidiDataOnIOThread, this, port, v, timestamp)); |
+} |
+ |
+void MidiMessageFilter::StartSessionOnIOThread() { |
+ TRACE_EVENT0("midi", "MidiMessageFilter::StartSessionOnIOThread"); |
+ DCHECK(io_message_loop_->BelongsToCurrentThread()); |
+ Send(new MidiHostMsg_StartSession()); |
+} |
+ |
+void MidiMessageFilter::SendMidiDataOnIOThread(uint32 port, |
+ const std::vector<uint8>& data, |
+ double timestamp) { |
+ DCHECK(io_message_loop_->BelongsToCurrentThread()); |
+ Send(new MidiHostMsg_SendData(port, data, timestamp)); |
+} |
+ |
+void MidiMessageFilter::EndSessionOnIOThread() { |
+ DCHECK(io_message_loop_->BelongsToCurrentThread()); |
+ Send(new MidiHostMsg_EndSession()); |
+} |
+ |
void MidiMessageFilter::Send(IPC::Message* message) { |
DCHECK(io_message_loop_->BelongsToCurrentThread()); |
if (!sender_) { |
@@ -61,7 +126,6 @@ void MidiMessageFilter::OnFilterAdded(IPC::Sender* sender) { |
void MidiMessageFilter::OnFilterRemoved() { |
DCHECK(io_message_loop_->BelongsToCurrentThread()); |
- |
// Once removed, a filter will not be used again. At this time all |
// delegates must be notified so they release their reference. |
OnChannelClosing(); |
@@ -72,74 +136,47 @@ void MidiMessageFilter::OnChannelClosing() { |
sender_ = NULL; |
} |
-void MidiMessageFilter::StartSession(blink::WebMIDIAccessorClient* client) { |
- // Generate and keep track of a "client id" which is sent to the browser |
- // to ask permission to talk to MIDI hardware. |
- // This id is handed back when we receive the answer in OnAccessApproved(). |
- if (clients_.find(client) == clients_.end()) { |
- int client_id = next_available_id_++; |
- clients_[client] = client_id; |
- |
- io_message_loop_->PostTask(FROM_HERE, |
- base::Bind(&MidiMessageFilter::StartSessionOnIOThread, this, |
- client_id)); |
- } |
-} |
- |
-void MidiMessageFilter::StartSessionOnIOThread(int client_id) { |
- Send(new MidiHostMsg_StartSession(client_id)); |
-} |
- |
-void MidiMessageFilter::RemoveClient(blink::WebMIDIAccessorClient* client) { |
- ClientsMap::iterator i = clients_.find(client); |
- if (i != clients_.end()) |
- clients_.erase(i); |
+void MidiMessageFilter::OnSessionStarted(media::MidiResult result, |
+ MidiPortInfoList inputs, |
+ MidiPortInfoList outputs) { |
+ TRACE_EVENT0("midi", "MidiMessageFilter::OnSessionStarted"); |
+ DCHECK(io_message_loop_->BelongsToCurrentThread()); |
+ // TODO(toyoshim): |inputs_| and |outputs_| should not be updated on |
+ // |io_message_loop_|. This should be fixed in a following change not to |
+ // distribute MidiPortInfo via OnSessionStarted(). |
+ // For now, this is safe because these are not updated later. |
+ inputs_ = inputs; |
+ outputs_ = outputs; |
+ // Handle on the main JS thread. |
+ main_message_loop_->PostTask( |
+ FROM_HERE, |
+ base::Bind(&MidiMessageFilter::HandleClientAdded, this, result)); |
} |
-// Received from browser. |
- |
-void MidiMessageFilter::OnSessionStarted( |
- int client_id, |
- media::MidiResult result, |
- MidiPortInfoList inputs, |
- MidiPortInfoList outputs) { |
+void MidiMessageFilter::OnDataReceived(uint32 port, |
+ const std::vector<uint8>& data, |
+ double timestamp) { |
+ TRACE_EVENT0("midi", "MidiMessageFilter::OnDataReceived"); |
+ DCHECK(io_message_loop_->BelongsToCurrentThread()); |
// Handle on the main JS thread. |
main_message_loop_->PostTask( |
FROM_HERE, |
- base::Bind(&MidiMessageFilter::HandleSessionStarted, this, |
- client_id, result, inputs, outputs)); |
+ base::Bind(&MidiMessageFilter::HandleDataReceived, this, port, data, |
+ timestamp)); |
} |
-void MidiMessageFilter::HandleSessionStarted( |
- int client_id, |
- media::MidiResult result, |
- MidiPortInfoList inputs, |
- MidiPortInfoList outputs) { |
- blink::WebMIDIAccessorClient* client = GetClientFromId(client_id); |
- if (!client) |
- return; |
- |
- if (result == media::MIDI_OK) { |
- // Add the client's input and output ports. |
- const bool active = true; |
- for (size_t i = 0; i < inputs.size(); ++i) { |
- client->didAddInputPort( |
- base::UTF8ToUTF16(inputs[i].id), |
- base::UTF8ToUTF16(inputs[i].manufacturer), |
- base::UTF8ToUTF16(inputs[i].name), |
- base::UTF8ToUTF16(inputs[i].version), |
- active); |
- } |
+void MidiMessageFilter::OnAcknowledgeSentData(size_t bytes_sent) { |
+ DCHECK(io_message_loop_->BelongsToCurrentThread()); |
+ main_message_loop_->PostTask( |
+ FROM_HERE, |
+ base::Bind(&MidiMessageFilter::HandleAckknowledgeSentData, this, |
+ bytes_sent)); |
+} |
- for (size_t i = 0; i < outputs.size(); ++i) { |
- client->didAddOutputPort( |
- base::UTF8ToUTF16(outputs[i].id), |
- base::UTF8ToUTF16(outputs[i].manufacturer), |
- base::UTF8ToUTF16(outputs[i].name), |
- base::UTF8ToUTF16(outputs[i].version), |
- active); |
- } |
- } |
+void MidiMessageFilter::HandleClientAdded(media::MidiResult result) { |
+ TRACE_EVENT0("midi", "MidiMessageFilter::HandleClientAdded"); |
+ DCHECK(main_message_loop_->BelongsToCurrentThread()); |
+ session_result_ = result; |
std::string error; |
std::string message; |
switch (result) { |
@@ -158,82 +195,52 @@ void MidiMessageFilter::HandleSessionStarted( |
message = "Unknown internal error occurred."; |
break; |
} |
- client->didStartSession(result == media::MIDI_OK, base::UTF8ToUTF16(error), |
- base::UTF8ToUTF16(message)); |
-} |
- |
-blink::WebMIDIAccessorClient* |
-MidiMessageFilter::GetClientFromId(int client_id) { |
- // Iterating like this seems inefficient, but in practice there generally |
- // will be very few clients (usually one). Additionally, this lookup |
- // usually happens one time during page load. So the performance hit is |
- // negligible. |
- for (ClientsMap::iterator i = clients_.begin(); i != clients_.end(); ++i) { |
- if ((*i).second == client_id) |
- return (*i).first; |
+ base::string16 error16 = base::UTF8ToUTF16(error); |
+ base::string16 message16 = base::UTF8ToUTF16(message); |
+ for (blink::WebMIDIAccessorClient* client : clients_waiting_session_queue_) { |
+ if (result == media::MIDI_OK) { |
+ // Add the client's input and output ports. |
+ const bool active = true; |
+ for (const auto& info : inputs_) { |
+ client->didAddInputPort( |
+ base::UTF8ToUTF16(info.id), |
+ base::UTF8ToUTF16(info.manufacturer), |
+ base::UTF8ToUTF16(info.name), |
+ base::UTF8ToUTF16(info.version), |
+ active); |
+ } |
+ |
+ for (const auto& info : outputs_) { |
+ client->didAddOutputPort( |
+ base::UTF8ToUTF16(info.id), |
+ base::UTF8ToUTF16(info.manufacturer), |
+ base::UTF8ToUTF16(info.name), |
+ base::UTF8ToUTF16(info.version), |
+ active); |
+ } |
+ } |
+ client->didStartSession(result == media::MIDI_OK, error16, message16); |
+ clients_.insert(client); |
} |
- return NULL; |
-} |
- |
-void MidiMessageFilter::OnDataReceived(uint32 port, |
- const std::vector<uint8>& data, |
- double timestamp) { |
- TRACE_EVENT0("midi", "MidiMessageFilter::OnDataReceived"); |
- |
- main_message_loop_->PostTask( |
- FROM_HERE, |
- base::Bind(&MidiMessageFilter::HandleDataReceived, this, |
- port, data, timestamp)); |
-} |
- |
-void MidiMessageFilter::OnAcknowledgeSentData(size_t bytes_sent) { |
- DCHECK_GE(unacknowledged_bytes_sent_, bytes_sent); |
- if (unacknowledged_bytes_sent_ >= bytes_sent) |
- unacknowledged_bytes_sent_ -= bytes_sent; |
+ clients_waiting_session_queue_.clear(); |
} |
void MidiMessageFilter::HandleDataReceived(uint32 port, |
const std::vector<uint8>& data, |
double timestamp) { |
- DCHECK(!data.empty()); |
TRACE_EVENT0("midi", "MidiMessageFilter::HandleDataReceived"); |
+ DCHECK(main_message_loop_->BelongsToCurrentThread()); |
+ DCHECK(!data.empty()); |
- for (ClientsMap::iterator i = clients_.begin(); i != clients_.end(); ++i) |
- (*i).first->didReceiveMIDIData(port, &data[0], data.size(), timestamp); |
-} |
- |
-void MidiMessageFilter::SendMidiData(uint32 port, |
- const uint8* data, |
- size_t length, |
- double timestamp) { |
- if (length > kMaxUnacknowledgedBytesSent) { |
- // TODO(toyoshim): buffer up the data to send at a later time. |
- // For now we're just dropping these bytes on the floor. |
- return; |
- } |
- |
- std::vector<uint8> v(data, data + length); |
- io_message_loop_->PostTask(FROM_HERE, |
- base::Bind(&MidiMessageFilter::SendMidiDataOnIOThread, this, |
- port, v, timestamp)); |
+ for (blink::WebMIDIAccessorClient* client : clients_) |
+ client->didReceiveMIDIData(port, &data[0], data.size(), timestamp); |
} |
-void MidiMessageFilter::SendMidiDataOnIOThread(uint32 port, |
- const std::vector<uint8>& data, |
- double timestamp) { |
- size_t n = data.size(); |
- if (n > kMaxUnacknowledgedBytesSent || |
- unacknowledged_bytes_sent_ > kMaxUnacknowledgedBytesSent || |
- n + unacknowledged_bytes_sent_ > kMaxUnacknowledgedBytesSent) { |
- // TODO(toyoshim): buffer up the data to send at a later time. |
- // For now we're just dropping these bytes on the floor. |
- return; |
- } |
- |
- unacknowledged_bytes_sent_ += n; |
- |
- // Send to the browser. |
- Send(new MidiHostMsg_SendData(port, data, timestamp)); |
+void MidiMessageFilter::HandleAckknowledgeSentData(size_t bytes_sent) { |
+ DCHECK(main_message_loop_->BelongsToCurrentThread()); |
+ DCHECK_GE(unacknowledged_bytes_sent_, bytes_sent); |
+ if (unacknowledged_bytes_sent_ >= bytes_sent) |
+ unacknowledged_bytes_sent_ -= bytes_sent; |
} |
} // namespace content |