1eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Copyright (c) 2013 The Chromium Authors. All rights reserved.
2eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// found in the LICENSE file.
4eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
5eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "content/browser/renderer_host/media/midi_host.h"
6eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
7eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/bind.h"
8eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/bind_helpers.h"
9eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/debug/trace_event.h"
10a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch#include "base/process/process.h"
11eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "content/browser/browser_main_loop.h"
12424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#include "content/browser/child_process_security_policy_impl.h"
13eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "content/browser/media/media_internals.h"
14eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "content/common/media/midi_messages.h"
15eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "content/public/browser/content_browser_client.h"
16eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "content/public/browser/media_observer.h"
17424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#include "content/public/browser/user_metrics.h"
18eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "media/midi/midi_manager.h"
19a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "media/midi/midi_message_queue.h"
20a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "media/midi/midi_message_util.h"
21eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
22eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing media::MIDIManager;
23eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochusing media::MIDIPortInfoList;
24eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
25a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)namespace content {
26a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)namespace {
27a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
28a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)// The total number of bytes which we're allowed to send to the OS
29a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)// before knowing that they have been successfully sent.
30a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)const size_t kMaxInFlightBytes = 10 * 1024 * 1024;  // 10 MB.
31a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
32a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)// We keep track of the number of bytes successfully sent to
33a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)// the hardware.  Every once in a while we report back to the renderer
34a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)// the number of bytes sent since the last report. This threshold determines
35a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)// how many bytes will be sent before reporting back to the renderer.
36a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)const size_t kAcknowledgementThresholdBytes = 1024 * 1024;  // 1 MB.
37a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
38a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)const uint8 kSysExMessage = 0xf0;
39a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)const uint8 kEndOfSysExMessage = 0xf7;
40a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
41a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)bool IsDataByte(uint8 data) {
42a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  return (data & 0x80) == 0;
43a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
44a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
45a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)bool IsSystemRealTimeMessage(uint8 data) {
46a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  return 0xf8 <= data && data <= 0xff;
47a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
48a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
49a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}  // namespace
50eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
51424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)MIDIHost::MIDIHost(int renderer_process_id, media::MIDIManager* midi_manager)
52424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    : renderer_process_id_(renderer_process_id),
53a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      has_sys_ex_permission_(false),
54424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      midi_manager_(midi_manager),
55a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      sent_bytes_in_flight_(0),
56a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      bytes_sent_since_last_acknowledgement_(0) {
57eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
58eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
59eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochMIDIHost::~MIDIHost() {
60eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (midi_manager_)
6158e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch    midi_manager_->EndSession(this);
62eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
63eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
64eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid MIDIHost::OnDestruct() const {
65eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  BrowserThread::DeleteOnIOThread::Destruct(this);
66eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
67eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
68eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch///////////////////////////////////////////////////////////////////////////////
69eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// IPC Messages handler
70eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochbool MIDIHost::OnMessageReceived(const IPC::Message& message,
71eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                 bool* message_was_ok) {
72eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  bool handled = true;
73eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  IPC_BEGIN_MESSAGE_MAP_EX(MIDIHost, message, *message_was_ok)
7458e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch    IPC_MESSAGE_HANDLER(MIDIHostMsg_StartSession, OnStartSession)
75eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    IPC_MESSAGE_HANDLER(MIDIHostMsg_SendData, OnSendData)
76eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    IPC_MESSAGE_UNHANDLED(handled = false)
77eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  IPC_END_MESSAGE_MAP_EX()
78eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
79eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return handled;
80eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
81eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
8258e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdochvoid MIDIHost::OnStartSession(int client_id) {
83eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  MIDIPortInfoList input_ports;
84eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  MIDIPortInfoList output_ports;
85eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
8658e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch  // Initialize devices and register to receive MIDI data.
8758e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch  bool success = false;
88eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  if (midi_manager_) {
8958e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch    success = midi_manager_->StartSession(this);
9058e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch    if (success) {
91eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      input_ports = midi_manager_->input_ports();
92eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      output_ports = midi_manager_->output_ports();
93a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      received_messages_queues_.clear();
94a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      received_messages_queues_.resize(input_ports.size());
95a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      // ChildSecurityPolicy is set just before OnStartSession by
96a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      // MIDIDispatcherHost. So we can safely cache the policy.
97a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      has_sys_ex_permission_ = ChildProcessSecurityPolicyImpl::GetInstance()->
98a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)          CanSendMIDISysExMessage(renderer_process_id_);
99eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    }
100eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
101eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
10258e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch  Send(new MIDIMsg_SessionStarted(
103eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch       client_id,
10458e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch       success,
105eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch       input_ports,
106eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch       output_ports));
107eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
108eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
109424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)void MIDIHost::OnSendData(uint32 port,
110eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                          const std::vector<uint8>& data,
111eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                          double timestamp) {
112a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  if (!midi_manager_)
113a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    return;
114a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
1153551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (data.empty())
1163551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return;
1173551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
118a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // Blink running in a renderer checks permission to raise a SecurityError
119a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // in JavaScript. The actual permission check for security purposes
120a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // happens here in the browser process.
121a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (!has_sys_ex_permission_ &&
122a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      (std::find(data.begin(), data.end(), kSysExMessage) != data.end())) {
123a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    RecordAction(UserMetricsAction("BadMessageTerminate_MIDI"));
124a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    BadMessageReceived();
125a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    return;
126424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  }
127a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
128a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (!IsValidWebMIDIData(data))
129a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    return;
130a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
131a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  base::AutoLock auto_lock(in_flight_lock_);
132a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // Sanity check that we won't send too much data.
133a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // TODO(yukawa): Consider to send an error event back to the renderer
134a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // after some future discussion in W3C.
135a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (data.size() + sent_bytes_in_flight_ > kMaxInFlightBytes)
136a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    return;
137a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  midi_manager_->DispatchSendMIDIData(this, port, data, timestamp);
138a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  sent_bytes_in_flight_ += data.size();
139eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
140eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
141eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid MIDIHost::ReceiveMIDIData(
142424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    uint32 port,
143eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    const uint8* data,
144eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    size_t length,
145eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    double timestamp) {
146eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  TRACE_EVENT0("midi", "MIDIHost::ReceiveMIDIData");
147a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
148a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (received_messages_queues_.size() <= port)
149a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    return;
150a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
151a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // Lazy initialization
152a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  if (received_messages_queues_[port] == NULL)
153a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    received_messages_queues_[port] = new media::MIDIMessageQueue(true);
154a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
155a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  received_messages_queues_[port]->Add(data, length);
156a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  std::vector<uint8> message;
157a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  while (true) {
158a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    received_messages_queues_[port]->Get(&message);
159a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    if (message.empty())
160a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      break;
161a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
162a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    // MIDI devices may send a system exclusive messages even if the renderer
163a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    // doesn't have a permission to receive it. Don't kill the renderer as
164a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    // OnSendData() does.
165a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    if (message[0] == kSysExMessage && !has_sys_ex_permission_)
166a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      continue;
167a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
168a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    // Send to the renderer.
169a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    Send(new MIDIMsg_DataReceived(port, message, timestamp));
170a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
171eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
172eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
173a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)void MIDIHost::AccumulateMIDIBytesSent(size_t n) {
174a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  {
175a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    base::AutoLock auto_lock(in_flight_lock_);
176a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    if (n <= sent_bytes_in_flight_)
177a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      sent_bytes_in_flight_ -= n;
178a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  }
179a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
180a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  if (bytes_sent_since_last_acknowledgement_ + n >=
181a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      bytes_sent_since_last_acknowledgement_)
182a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    bytes_sent_since_last_acknowledgement_ += n;
183a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
184a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  if (bytes_sent_since_last_acknowledgement_ >=
185a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      kAcknowledgementThresholdBytes) {
186a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    Send(new MIDIMsg_AcknowledgeSentData(
187a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)        bytes_sent_since_last_acknowledgement_));
188a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    bytes_sent_since_last_acknowledgement_ = 0;
189a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  }
190a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)}
191a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
192a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// static
193a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)bool MIDIHost::IsValidWebMIDIData(const std::vector<uint8>& data) {
194a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  bool in_sysex = false;
195a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  size_t waiting_data_length = 0;
196a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  for (size_t i = 0; i < data.size(); ++i) {
197a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    const uint8 current = data[i];
198a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    if (IsSystemRealTimeMessage(current))
199a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      continue;  // Real time message can be placed at any point.
200a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    if (waiting_data_length > 0) {
201a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      if (!IsDataByte(current))
202a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        return false;  // Error: |current| should have been data byte.
203a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      --waiting_data_length;
204a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      continue;  // Found data byte as expected.
205a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    }
206a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    if (in_sysex) {
207a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      if (data[i] == kEndOfSysExMessage)
208a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        in_sysex = false;
209a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      else if (!IsDataByte(current))
210a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        return false;  // Error: |current| should have been data byte.
211a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      continue;  // Found data byte as expected.
212a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    }
213a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    if (current == kSysExMessage) {
214a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      in_sysex = true;
215a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      continue;  // Found SysEX
216a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    }
217a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    waiting_data_length = media::GetMIDIMessageLength(current);
218a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    if (waiting_data_length == 0)
219a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      return false;  // Error: |current| should have been a valid status byte.
220a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    --waiting_data_length;  // Found status byte
221a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
222a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  return waiting_data_length == 0 && !in_sysex;
223a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
224a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
225eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}  // namespace content
226