Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(34)

Side by Side Diff: content/renderer/media/midi_message_filter.cc

Issue 16025005: Web MIDI API back-end (work-in-progress) (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: add stub for non-OSX MIDIManagers Created 7 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "content/renderer/media/midi_message_filter.h"
6
7 #include "base/bind.h"
8 #include "base/debug/trace_event.h"
9 #include "base/message_loop_proxy.h"
10 #include "base/utf_string_conversions.h"
11 #include "content/common/media/midi_messages.h"
12 #include "content/renderer/render_thread_impl.h"
13 #include "ipc/ipc_logging.h"
14
15 using media::MIDIPortInfoList;
16 using base::AutoLock;
17
18 namespace content {
19
20 int MIDIMessageFilter::next_available_id_ = 0;
21
22 MIDIMessageFilter::MIDIMessageFilter(
23 const scoped_refptr<base::MessageLoopProxy>& io_message_loop)
24 : channel_(NULL),
25 io_message_loop_(io_message_loop) {
26 }
27
28 MIDIMessageFilter::~MIDIMessageFilter() {}
29
30 void MIDIMessageFilter::Send(IPC::Message* message) {
31 DCHECK(io_message_loop_->BelongsToCurrentThread());
32 if (!channel_) {
33 delete message;
34 } else {
35 channel_->Send(message);
36 }
37 }
38
39 bool MIDIMessageFilter::OnMessageReceived(const IPC::Message& message) {
40 DCHECK(io_message_loop_->BelongsToCurrentThread());
41 bool handled = true;
42 IPC_BEGIN_MESSAGE_MAP(MIDIMessageFilter, message)
43 IPC_MESSAGE_HANDLER(MIDIMsg_AccessApproved, OnAccessApproved)
44 IPC_MESSAGE_HANDLER(MIDIMsg_DataReceived, OnDataReceived)
45 IPC_MESSAGE_UNHANDLED(handled = false)
46 IPC_END_MESSAGE_MAP()
47 return handled;
48 }
49
50 void MIDIMessageFilter::OnFilterAdded(IPC::Channel* channel) {
51 DCHECK(io_message_loop_->BelongsToCurrentThread());
52 channel_ = channel;
53 }
54
55 void MIDIMessageFilter::OnFilterRemoved() {
56 DCHECK(io_message_loop_->BelongsToCurrentThread());
57
58 // Once removed, a filter will not be used again. At this time all
59 // delegates must be notified so they release their reference.
60 OnChannelClosing();
61 }
62
63 void MIDIMessageFilter::OnChannelClosing() {
64 DCHECK(io_message_loop_->BelongsToCurrentThread());
65 channel_ = NULL;
66 }
67
68 void MIDIMessageFilter::RequestAccess(
69 WebKit::WebMIDIAccessorClient* client, int access) {
70 AutoLock auto_lock(clients_lock_);
71
72 // Get the main thread message loop.
73 if (!client_message_loop_)
74 client_message_loop_ = base::MessageLoopProxy::current();
75 else
76 CHECK(client_message_loop_ == base::MessageLoopProxy::current());
77
78 // Generate and keep track of a "client id" which is sent to the browser
79 // to ask permission to talk to MIDI hardware.
80 // This id is handed back when we receive the answer in OnAccessApproved().
81 if (clients_.find(client) == clients_.end()) {
82 int client_id = next_available_id_++;
83 clients_[client] = client_id;
84 Send(new MIDIHostMsg_RequestAccess(client_id, access));
piman 2013/06/20 20:16:20 Which thread is this running on? The doc in the he
Chris Rogers 2013/06/21 23:04:11 Yes, good point. Fixed.
85 }
86 };
87
88 void MIDIMessageFilter::RemoveClient(WebKit::WebMIDIAccessorClient* client) {
89 AutoLock auto_lock(clients_lock_);
90 ClientsMap::iterator i = clients_.find(client);
91 if (i != clients_.end())
92 clients_.erase(i);
93 };
94
95 // Received from browser.
96
97 void MIDIMessageFilter::OnAccessApproved(
98 int client_id,
99 int access,
100 bool success,
101 MIDIPortInfoList inputs,
102 MIDIPortInfoList outputs) {
103 if (client_message_loop_) {
104 // Handle on the main JS thread.
105 client_message_loop_->PostTask(FROM_HERE,
106 base::Bind(&MIDIMessageFilter::HandleAccessApproved, this,
107 client_id, access, success, inputs, outputs));
108 }
109 }
110
111 void MIDIMessageFilter::HandleAccessApproved(
112 int client_id,
113 int access,
114 bool success,
115 MIDIPortInfoList inputs,
116 MIDIPortInfoList outputs) {
117 AutoLock auto_lock(clients_lock_);
118
119 WebKit::WebMIDIAccessorClient* client = GetClientFromId(client_id);
120 if (!client)
121 return;
122
123 if (success) {
124 // Add the client's input and output ports.
125 for (size_t i = 0; i < inputs.size(); ++i) {
126 client->addInputPort(
127 UTF8ToUTF16(inputs[i].id),
128 UTF8ToUTF16(inputs[i].manufacturer),
129 UTF8ToUTF16(inputs[i].name),
130 UTF8ToUTF16(inputs[i].version));
131 }
132
133 for (size_t i = 0; i < outputs.size(); ++i) {
134 client->addOutputPort(
135 UTF8ToUTF16(outputs[i].id),
136 UTF8ToUTF16(outputs[i].manufacturer),
137 UTF8ToUTF16(outputs[i].name),
138 UTF8ToUTF16(outputs[i].version));
139 }
140 }
141
142 client->accessApproved(success);
143 }
144
145 WebKit::WebMIDIAccessorClient*
146 MIDIMessageFilter::GetClientFromId(int client_id) {
147 // Iterating like this seems inefficient, but in practice there generally
148 // will be very few clients (usually one). Additionally, this lookup
149 // usually happens one time during page load. So the performance hit is
150 // negligible.
151 for (ClientsMap::iterator i = clients_.begin(); i != clients_.end(); ++i) {
152 if ((*i).second == client_id)
153 return (*i).first;
154 }
155 return NULL;
156 }
157
158 void MIDIMessageFilter::OnDataReceived(int port,
159 const std::vector<uint8>& data,
160 double timestamp) {
161 TRACE_EVENT0("midi", "MIDIMessageFilter::OnDataReceived");
162
163 if (client_message_loop_) {
164 client_message_loop_->PostTask(FROM_HERE,
165 base::Bind(&MIDIMessageFilter::HandleDataReceived, this,
166 port, data, timestamp));
167 }
168 }
169
170 void MIDIMessageFilter::HandleDataReceived(int port,
171 const std::vector<uint8>& data,
172 double timestamp) {
173 TRACE_EVENT0("midi", "MIDIMessageFilter::HandleDataReceived");
174
175 AutoLock auto_lock(clients_lock_);
176 for (ClientsMap::iterator i = clients_.begin(); i != clients_.end(); ++i)
177 (*i).first->receiveMIDIData(port, data.data(), data.size(), timestamp);
178 }
179
180 void MIDIMessageFilter::SendMIDIData(int port_index,
181 const uint8* data,
182 size_t length,
183 double timestamp) {
184 // Send to the browser.
185 std::vector<uint8> v(data, data + length);
palmer 2013/06/19 21:39:15 Same copying-due-to-interface issue here. Perhaps
Chris Rogers 2013/06/20 17:41:33 Yeah, I think at some point we have to take the hi
186 Send(new MIDIHostMsg_SendData(port_index, v, timestamp));
piman 2013/06/20 20:16:20 Is this called on the client thread or IO thread?
Chris Rogers 2013/06/21 23:04:11 In this CL I have the code initially written to Po
187 }
188
189 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698