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::midi::MidiManager
{
72 void DispatchSendMidiData(media::midi::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
,
87 media::midi::MidiManager
* midi_manager
)
88 : MidiHost(renderer_process_id
, midi_manager
) {}
91 ~MidiHostForTesting() override
{}
93 // BrowserMessageFilter implementation.
94 // Override ShutdownForBadMessage() to do nothing since the original
95 // implementation to kill a malicious renderer process causes a check failure
97 void ShutdownForBadMessage() override
{}
100 class MidiHostTest
: public testing::Test
{
103 : io_browser_thread_(BrowserThread::IO
, &message_loop_
),
104 host_(new MidiHostForTesting(kRenderProcessId
, &manager_
)),
105 data_(kNoteOn
, kNoteOn
+ arraysize(kNoteOn
)),
109 void AddOutputPort() {
110 const std::string id
= base::StringPrintf("i-can-%d", port_id_
++);
111 const std::string
manufacturer("yukatan");
112 const std::string
name("doki-doki-pi-pine");
113 const std::string
version("3.14159265359");
114 media::midi::MidiPortState state
= media::midi::MIDI_PORT_CONNECTED
;
115 media::midi::MidiPortInfo
info(id
, manufacturer
, name
, version
, state
);
117 host_
->AddOutputPort(info
);
120 void OnSendData(uint32 port
) {
121 scoped_ptr
<IPC::Message
> message(
122 new MidiHostMsg_SendData(port
, data_
, 0.0));
123 host_
->OnMessageReceived(*message
.get());
126 size_t GetEventSize() const {
127 return manager_
.events_
.size();
130 void CheckSendEventAt(size_t at
, uint32 port
) {
131 EXPECT_EQ(DISPATCH_SEND_MIDI_DATA
, manager_
.events_
[at
].type
);
132 EXPECT_EQ(port
, manager_
.events_
[at
].port_index
);
133 EXPECT_EQ(data_
, manager_
.events_
[at
].data
);
134 EXPECT_EQ(0.0, manager_
.events_
[at
].timestamp
);
137 void RunLoopUntilIdle() {
138 base::RunLoop run_loop
;
139 run_loop
.RunUntilIdle();
143 base::MessageLoop message_loop_
;
144 TestBrowserThread io_browser_thread_
;
146 FakeMidiManager manager_
;
147 scoped_refptr
<MidiHostForTesting
> host_
;
148 std::vector
<uint8
> data_
;
151 DISALLOW_COPY_AND_ASSIGN(MidiHostTest
);
156 TEST_F(MidiHostTest
, IsValidWebMIDIData
) {
157 // Test single event scenario
158 EXPECT_TRUE(MidiHost::IsValidWebMIDIData(AsVector(kGMOn
)));
159 EXPECT_TRUE(MidiHost::IsValidWebMIDIData(AsVector(kGSOn
)));
160 EXPECT_TRUE(MidiHost::IsValidWebMIDIData(AsVector(kNoteOn
)));
161 EXPECT_TRUE(MidiHost::IsValidWebMIDIData(AsVector(kChannelPressure
)));
162 EXPECT_TRUE(MidiHost::IsValidWebMIDIData(AsVector(kTimingClock
)));
163 EXPECT_FALSE(MidiHost::IsValidWebMIDIData(AsVector(kBrokenData1
)));
164 EXPECT_FALSE(MidiHost::IsValidWebMIDIData(AsVector(kBrokenData2
)));
165 EXPECT_FALSE(MidiHost::IsValidWebMIDIData(AsVector(kBrokenData3
)));
166 EXPECT_FALSE(MidiHost::IsValidWebMIDIData(AsVector(kDataByte0
)));
168 // MIDI running status should be disallowed
169 EXPECT_FALSE(MidiHost::IsValidWebMIDIData(
170 AsVector(kNoteOnWithRunningStatus
)));
171 EXPECT_FALSE(MidiHost::IsValidWebMIDIData(
172 AsVector(kChannelPressureWithRunningStatus
)));
174 // Multiple messages are allowed as long as each of them is complete.
176 std::vector
<uint8
> buffer
;
177 PushToVector(kGMOn
, &buffer
);
178 PushToVector(kNoteOn
, &buffer
);
179 PushToVector(kGSOn
, &buffer
);
180 PushToVector(kTimingClock
, &buffer
);
181 PushToVector(kNoteOn
, &buffer
);
182 EXPECT_TRUE(MidiHost::IsValidWebMIDIData(buffer
));
183 PushToVector(kBrokenData1
, &buffer
);
184 EXPECT_FALSE(MidiHost::IsValidWebMIDIData(buffer
));
187 // MIDI realtime message can be placed at any position.
189 const uint8 kNoteOnWithRealTimeClock
[] = {
190 0x90, 0xf8, 0x3c, 0x7f, 0x90, 0xf8, 0x3c, 0xf8, 0x7f, 0xf8,
192 EXPECT_TRUE(MidiHost::IsValidWebMIDIData(
193 AsVector(kNoteOnWithRealTimeClock
)));
195 const uint8 kGMOnWithRealTimeClock
[] = {
196 0xf0, 0xf8, 0x7e, 0x7f, 0x09, 0x01, 0xf8, 0xf7,
198 EXPECT_TRUE(MidiHost::IsValidWebMIDIData(
199 AsVector(kGMOnWithRealTimeClock
)));
203 // Test if sending data to out of range port is ignored.
204 TEST_F(MidiHostTest
, OutputPortCheck
) {
205 // Only one output port is available.
208 // Sending data to port 0 should be delivered.
212 EXPECT_EQ(1U, GetEventSize());
213 CheckSendEventAt(0, port0
);
215 // Sending data to port 1 should not be delivered.
219 EXPECT_EQ(1U, GetEventSize());
221 // Two output ports are available from now on.
224 // Sending data to port 0 and 1 should be delivered now.
228 EXPECT_EQ(3U, GetEventSize());
229 CheckSendEventAt(1, port0
);
230 CheckSendEventAt(2, port1
);
233 } // namespace conent