1 // Copyright 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.
5 #include "content/browser/media/midi_host.h"
7 #include "base/message_loop/message_loop.h"
8 #include "base/run_loop.h"
9 #include "base/strings/stringprintf.h"
10 #include "content/common/media/midi_messages.h"
11 #include "content/public/test/test_browser_thread.h"
12 #include "media/midi/midi_manager.h"
13 #include "testing/gtest/include/gtest/gtest.h"
18 const uint8 kGMOn
[] = { 0xf0, 0x7e, 0x7f, 0x09, 0x01, 0xf7 };
19 const uint8 kGSOn
[] = {
20 0xf0, 0x41, 0x10, 0x42, 0x12, 0x40, 0x00, 0x7f, 0x00, 0x41, 0xf7,
22 const uint8 kNoteOn
[] = { 0x90, 0x3c, 0x7f };
23 const uint8 kNoteOnWithRunningStatus
[] = {
24 0x90, 0x3c, 0x7f, 0x3c, 0x7f, 0x3c, 0x7f,
26 const uint8 kChannelPressure
[] = { 0xd0, 0x01 };
27 const uint8 kChannelPressureWithRunningStatus
[] = {
28 0xd0, 0x01, 0x01, 0x01,
30 const uint8 kTimingClock
[] = { 0xf8 };
31 const uint8 kBrokenData1
[] = { 0x90 };
32 const uint8 kBrokenData2
[] = { 0xf7 };
33 const uint8 kBrokenData3
[] = { 0xf2, 0x00 };
34 const uint8 kDataByte0
[] = { 0x00 };
36 const int kRenderProcessId
= 0;
38 template <typename T
, size_t N
>
39 const std::vector
<T
> AsVector(const T(&data
)[N
]) {
40 std::vector
<T
> buffer
;
41 buffer
.insert(buffer
.end(), data
, data
+ N
);
45 template <typename T
, size_t N
>
46 void PushToVector(const T(&data
)[N
], std::vector
<T
>* buffer
) {
47 buffer
->insert(buffer
->end(), data
, data
+ N
);
51 DISPATCH_SEND_MIDI_DATA
,
55 MidiEvent(MidiEventType in_type
,
57 const std::vector
<uint8
>& in_data
,
60 port_index(in_port_index
),
62 timestamp(in_timestamp
) {}
66 std::vector
<uint8
> data
;
70 class FakeMidiManager
: public media::MidiManager
{
72 void DispatchSendMidiData(media::MidiManagerClient
* client
,
74 const std::vector
<uint8
>& data
,
75 double timestamp
) override
{
76 events_
.push_back(MidiEvent(DISPATCH_SEND_MIDI_DATA
,
81 std::vector
<MidiEvent
> events_
;
84 class MidiHostForTesting
: public MidiHost
{
86 MidiHostForTesting(int renderer_process_id
, media::MidiManager
* midi_manager
)
87 : MidiHost(renderer_process_id
, midi_manager
) {}
90 ~MidiHostForTesting() override
{}
92 // BrowserMessageFilter implementation.
93 // Override BadMessageReceived() so to do nothing since the original
94 // implementation to kill a malicious renderer process causes a check failure
96 void BadMessageReceived() override
{}
99 class MidiHostTest
: public testing::Test
{
102 : io_browser_thread_(BrowserThread::IO
, &message_loop_
),
103 host_(new MidiHostForTesting(kRenderProcessId
, &manager_
)),
104 data_(kNoteOn
, kNoteOn
+ arraysize(kNoteOn
)),
108 void AddOutputPort() {
109 const std::string id
= base::StringPrintf("i-can-%d", port_id_
++);
110 const std::string
manufacturer("yukatan");
111 const std::string
name("doki-doki-pi-pine");
112 const std::string
version("3.14159265359");
113 media::MidiPortState state
= media::MIDI_PORT_CONNECTED
;
114 media::MidiPortInfo
info(id
, manufacturer
, name
, version
, state
);
116 host_
->AddOutputPort(info
);
119 void OnSendData(uint32 port
) {
120 scoped_ptr
<IPC::Message
> message(
121 new MidiHostMsg_SendData(port
, data_
, 0.0));
122 host_
->OnMessageReceived(*message
.get());
125 size_t GetEventSize() const {
126 return manager_
.events_
.size();
129 void CheckSendEventAt(size_t at
, uint32 port
) {
130 EXPECT_EQ(DISPATCH_SEND_MIDI_DATA
, manager_
.events_
[at
].type
);
131 EXPECT_EQ(port
, manager_
.events_
[at
].port_index
);
132 EXPECT_EQ(data_
, manager_
.events_
[at
].data
);
133 EXPECT_EQ(0.0, manager_
.events_
[at
].timestamp
);
136 void RunLoopUntilIdle() {
137 base::RunLoop run_loop
;
138 run_loop
.RunUntilIdle();
142 base::MessageLoop message_loop_
;
143 TestBrowserThread io_browser_thread_
;
145 FakeMidiManager manager_
;
146 scoped_refptr
<MidiHostForTesting
> host_
;
147 std::vector
<uint8
> data_
;
150 DISALLOW_COPY_AND_ASSIGN(MidiHostTest
);
155 TEST_F(MidiHostTest
, IsValidWebMIDIData
) {
156 // Test single event scenario
157 EXPECT_TRUE(MidiHost::IsValidWebMIDIData(AsVector(kGMOn
)));
158 EXPECT_TRUE(MidiHost::IsValidWebMIDIData(AsVector(kGSOn
)));
159 EXPECT_TRUE(MidiHost::IsValidWebMIDIData(AsVector(kNoteOn
)));
160 EXPECT_TRUE(MidiHost::IsValidWebMIDIData(AsVector(kChannelPressure
)));
161 EXPECT_TRUE(MidiHost::IsValidWebMIDIData(AsVector(kTimingClock
)));
162 EXPECT_FALSE(MidiHost::IsValidWebMIDIData(AsVector(kBrokenData1
)));
163 EXPECT_FALSE(MidiHost::IsValidWebMIDIData(AsVector(kBrokenData2
)));
164 EXPECT_FALSE(MidiHost::IsValidWebMIDIData(AsVector(kBrokenData3
)));
165 EXPECT_FALSE(MidiHost::IsValidWebMIDIData(AsVector(kDataByte0
)));
167 // MIDI running status should be disallowed
168 EXPECT_FALSE(MidiHost::IsValidWebMIDIData(
169 AsVector(kNoteOnWithRunningStatus
)));
170 EXPECT_FALSE(MidiHost::IsValidWebMIDIData(
171 AsVector(kChannelPressureWithRunningStatus
)));
173 // Multiple messages are allowed as long as each of them is complete.
175 std::vector
<uint8
> buffer
;
176 PushToVector(kGMOn
, &buffer
);
177 PushToVector(kNoteOn
, &buffer
);
178 PushToVector(kGSOn
, &buffer
);
179 PushToVector(kTimingClock
, &buffer
);
180 PushToVector(kNoteOn
, &buffer
);
181 EXPECT_TRUE(MidiHost::IsValidWebMIDIData(buffer
));
182 PushToVector(kBrokenData1
, &buffer
);
183 EXPECT_FALSE(MidiHost::IsValidWebMIDIData(buffer
));
186 // MIDI realtime message can be placed at any position.
188 const uint8 kNoteOnWithRealTimeClock
[] = {
189 0x90, 0xf8, 0x3c, 0x7f, 0x90, 0xf8, 0x3c, 0xf8, 0x7f, 0xf8,
191 EXPECT_TRUE(MidiHost::IsValidWebMIDIData(
192 AsVector(kNoteOnWithRealTimeClock
)));
194 const uint8 kGMOnWithRealTimeClock
[] = {
195 0xf0, 0xf8, 0x7e, 0x7f, 0x09, 0x01, 0xf8, 0xf7,
197 EXPECT_TRUE(MidiHost::IsValidWebMIDIData(
198 AsVector(kGMOnWithRealTimeClock
)));
202 // Test if sending data to out of range port is ignored.
203 TEST_F(MidiHostTest
, OutputPortCheck
) {
204 // Only one output port is available.
207 // Sending data to port 0 should be delivered.
211 EXPECT_EQ(1U, GetEventSize());
212 CheckSendEventAt(0, port0
);
214 // Sending data to port 1 should not be delivered.
218 EXPECT_EQ(1U, GetEventSize());
220 // Two output ports are available from now on.
223 // Sending data to port 0 and 1 should be delivered now.
227 EXPECT_EQ(3U, GetEventSize());
228 CheckSendEventAt(1, port0
);
229 CheckSendEventAt(2, port1
);
232 } // namespace conent