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