1 // Copyright (c) 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. 4 5 #include "content/browser/renderer_host/media/midi_host.h" 6 7 #include "base/bind.h" 8 #include "base/bind_helpers.h" 9 #include "base/debug/trace_event.h" 10 #include "base/process/process.h" 11 #include "content/browser/browser_main_loop.h" 12 #include "content/browser/media/media_internals.h" 13 #include "content/common/media/midi_messages.h" 14 #include "content/public/browser/content_browser_client.h" 15 #include "content/public/browser/media_observer.h" 16 #include "media/midi/midi_manager.h" 17 18 using media::MIDIManager; 19 using media::MIDIPortInfoList; 20 21 // The total number of bytes which we're allowed to send to the OS 22 // before knowing that they have been successfully sent. 23 static const size_t kMaxInFlightBytes = 10 * 1024 * 1024; // 10 MB. 24 25 // We keep track of the number of bytes successfully sent to 26 // the hardware. Every once in a while we report back to the renderer 27 // the number of bytes sent since the last report. This threshold determines 28 // how many bytes will be sent before reporting back to the renderer. 29 static const size_t kAcknowledgementThresholdBytes = 1024 * 1024; // 1 MB. 30 31 static const uint8 kSysExMessage = 0xf0; 32 33 namespace content { 34 35 MIDIHost::MIDIHost(media::MIDIManager* midi_manager) 36 : midi_manager_(midi_manager), 37 sent_bytes_in_flight_(0), 38 bytes_sent_since_last_acknowledgement_(0) { 39 } 40 41 MIDIHost::~MIDIHost() { 42 if (midi_manager_) 43 midi_manager_->EndSession(this); 44 } 45 46 void MIDIHost::OnChannelClosing() { 47 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 48 49 BrowserMessageFilter::OnChannelClosing(); 50 } 51 52 void MIDIHost::OnDestruct() const { 53 BrowserThread::DeleteOnIOThread::Destruct(this); 54 } 55 56 /////////////////////////////////////////////////////////////////////////////// 57 // IPC Messages handler 58 bool MIDIHost::OnMessageReceived(const IPC::Message& message, 59 bool* message_was_ok) { 60 bool handled = true; 61 IPC_BEGIN_MESSAGE_MAP_EX(MIDIHost, message, *message_was_ok) 62 IPC_MESSAGE_HANDLER(MIDIHostMsg_StartSession, OnStartSession) 63 IPC_MESSAGE_HANDLER(MIDIHostMsg_SendData, OnSendData) 64 IPC_MESSAGE_UNHANDLED(handled = false) 65 IPC_END_MESSAGE_MAP_EX() 66 67 return handled; 68 } 69 70 void MIDIHost::OnStartSession(int client_id) { 71 MIDIPortInfoList input_ports; 72 MIDIPortInfoList output_ports; 73 74 // Initialize devices and register to receive MIDI data. 75 bool success = false; 76 if (midi_manager_) { 77 success = midi_manager_->StartSession(this); 78 if (success) { 79 input_ports = midi_manager_->input_ports(); 80 output_ports = midi_manager_->output_ports(); 81 } 82 } 83 84 Send(new MIDIMsg_SessionStarted( 85 client_id, 86 success, 87 input_ports, 88 output_ports)); 89 } 90 91 void MIDIHost::OnSendData(int port, 92 const std::vector<uint8>& data, 93 double timestamp) { 94 if (!midi_manager_) 95 return; 96 97 base::AutoLock auto_lock(in_flight_lock_); 98 99 // Sanity check that we won't send too much. 100 if (sent_bytes_in_flight_ > kMaxInFlightBytes || 101 data.size() > kMaxInFlightBytes || 102 data.size() + sent_bytes_in_flight_ > kMaxInFlightBytes) 103 return; 104 105 // For now disallow all System Exclusive messages even if we 106 // have permission. 107 // TODO(toyoshim): allow System Exclusive if browser has granted 108 // this client access. We'll likely need to pass a GURL 109 // here to compare against our permissions. 110 if (data.size() > 0 && data[0] >= kSysExMessage) 111 return; 112 113 #if defined(OS_ANDROID) 114 // TODO(toyoshim): figure out why data() method does not compile on Android. 115 NOTIMPLEMENTED(); 116 #else 117 midi_manager_->DispatchSendMIDIData( 118 this, 119 port, 120 data.data(), 121 data.size(), 122 timestamp); 123 #endif 124 125 sent_bytes_in_flight_ += data.size(); 126 } 127 128 void MIDIHost::ReceiveMIDIData( 129 int port_index, 130 const uint8* data, 131 size_t length, 132 double timestamp) { 133 TRACE_EVENT0("midi", "MIDIHost::ReceiveMIDIData"); 134 135 // For now disallow all System Exclusive messages even if we 136 // have permission. 137 // TODO(toyoshim): allow System Exclusive if browser has granted 138 // this client access. We'll likely need to pass a GURL 139 // here to compare against our permissions. 140 if (length > 0 && data[0] >= kSysExMessage) 141 return; 142 143 // Send to the renderer. 144 std::vector<uint8> v(data, data + length); 145 Send(new MIDIMsg_DataReceived(port_index, v, timestamp)); 146 } 147 148 void MIDIHost::AccumulateMIDIBytesSent(size_t n) { 149 { 150 base::AutoLock auto_lock(in_flight_lock_); 151 if (n <= sent_bytes_in_flight_) 152 sent_bytes_in_flight_ -= n; 153 } 154 155 if (bytes_sent_since_last_acknowledgement_ + n >= 156 bytes_sent_since_last_acknowledgement_) 157 bytes_sent_since_last_acknowledgement_ += n; 158 159 if (bytes_sent_since_last_acknowledgement_ >= 160 kAcknowledgementThresholdBytes) { 161 Send(new MIDIMsg_AcknowledgeSentData( 162 bytes_sent_since_last_acknowledgement_)); 163 bytes_sent_since_last_acknowledgement_ = 0; 164 } 165 } 166 167 } // namespace content 168