Home | History | Annotate | Download | only in media
      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