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 5f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "content/browser/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 225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)using media::MidiManager; 235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)using 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)bool IsDataByte(uint8 data) { 39a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return (data & 0x80) == 0; 40a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 41a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 42a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)bool IsSystemRealTimeMessage(uint8 data) { 43a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return 0xf8 <= data && data <= 0xff; 44a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 45a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 46a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} // namespace 47eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)using media::kSysExByte; 495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)using media::kEndOfSysExByte; 505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)MidiHost::MidiHost(int renderer_process_id, media::MidiManager* midi_manager) 525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) : BrowserMessageFilter(MidiMsgStart), 535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) renderer_process_id_(renderer_process_id), 54a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) has_sys_ex_permission_(false), 55424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) midi_manager_(midi_manager), 56a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) sent_bytes_in_flight_(0), 57a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) bytes_sent_since_last_acknowledgement_(0) { 58eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 59eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)MidiHost::~MidiHost() { 61eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (midi_manager_) 6258e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch midi_manager_->EndSession(this); 63eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 64eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void MidiHost::OnDestruct() const { 66eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch BrowserThread::DeleteOnIOThread::Destruct(this); 67eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 68eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 69eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// IPC Messages handler 70cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)bool MidiHost::OnMessageReceived(const IPC::Message& message) { 71eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch bool handled = true; 72cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) IPC_BEGIN_MESSAGE_MAP(MidiHost, message) 735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) IPC_MESSAGE_HANDLER(MidiHostMsg_StartSession, OnStartSession) 745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) IPC_MESSAGE_HANDLER(MidiHostMsg_SendData, OnSendData) 75eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch IPC_MESSAGE_UNHANDLED(handled = false) 76cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) IPC_END_MESSAGE_MAP() 77eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 78eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch return handled; 79eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 80eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void MidiHost::OnStartSession(int client_id) { 82a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch if (midi_manager_) 83a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch midi_manager_->StartSession(this, client_id); 84eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 85eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void MidiHost::OnSendData(uint32 port, 87eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const std::vector<uint8>& data, 88eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch double timestamp) { 89a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) if (!midi_manager_) 90a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) return; 91a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 923551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) if (data.empty()) 933551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) return; 943551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 95a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // Blink running in a renderer checks permission to raise a SecurityError 96a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // in JavaScript. The actual permission check for security purposes 97a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // happens here in the browser process. 98a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (!has_sys_ex_permission_ && 995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) std::find(data.begin(), data.end(), kSysExByte) != data.end()) { 1005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) RecordAction(base::UserMetricsAction("BadMessageTerminate_MIDI")); 101a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) BadMessageReceived(); 102a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) return; 103424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) } 104a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 105a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) if (!IsValidWebMIDIData(data)) 106a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return; 107a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 1085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) { 1095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::AutoLock auto_lock(in_flight_lock_); 1105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Sanity check that we won't send too much data. 1115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // TODO(yukawa): Consider to send an error event back to the renderer 1125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // after some future discussion in W3C. 1135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (data.size() + sent_bytes_in_flight_ > kMaxInFlightBytes) 1145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return; 1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) sent_bytes_in_flight_ += data.size(); 1165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) midi_manager_->DispatchSendMidiData(this, port, data, timestamp); 118eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 119eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 120a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochvoid MidiHost::CompleteStartSession(int client_id, media::MidiResult result) { 121a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch MidiPortInfoList input_ports; 122a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch MidiPortInfoList output_ports; 123a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch 124010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) if (result == media::MIDI_OK) { 125a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch input_ports = midi_manager_->input_ports(); 126a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch output_ports = midi_manager_->output_ports(); 127a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch received_messages_queues_.clear(); 128a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch received_messages_queues_.resize(input_ports.size()); 129a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch // ChildSecurityPolicy is set just before OnStartSession by 130a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch // MidiDispatcherHost. So we can safely cache the policy. 131a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch has_sys_ex_permission_ = ChildProcessSecurityPolicyImpl::GetInstance()-> 132a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch CanSendMidiSysExMessage(renderer_process_id_); 133a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch } 134a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch 135a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch Send(new MidiMsg_SessionStarted(client_id, 136010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) result, 137a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch input_ports, 138a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch output_ports)); 139a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch} 140a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch 1415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void MidiHost::ReceiveMidiData( 142424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) uint32 port, 143eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const uint8* data, 144eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch size_t length, 145eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch double timestamp) { 1465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 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) 1535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (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. 1655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (message[0] == kSysExByte && !has_sys_ex_permission_) 166a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) continue; 167a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 168a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // Send to the renderer. 1695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) Send(new MidiMsg_DataReceived(port, message, timestamp)); 170a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 171eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch} 172eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 1735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (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) { 1865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (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 1935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (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) { 2075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (data[i] == kEndOfSysExByte) 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) } 2135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (current == kSysExByte) { 214a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) in_sysex = true; 215a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) continue; // Found SysEX 216a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 2175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (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